Skip to content

Instantly share code, notes, and snippets.

@pokap
Last active August 9, 2022 15:08
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pokap/ac5fce3570c9bec3a87a8908bcbd0bbc to your computer and use it in GitHub Desktop.
Save pokap/ac5fce3570c9bec3a87a8908bcbd0bbc to your computer and use it in GitHub Desktop.
[PHPunit] assert two arrays are equal, but ignore orders
<?php
trait ArrayTestCaseTrait
{
/**
* Asserts that two associative arrays are similar.
*
* Both arrays must have the same indexes with identical values
* without respect to key ordering
*
* @param array $expected
* @param array $array
*/
protected function assertArraySimilar(array $expected, array $array)
{
$this->assertTrue(count(array_diff_key($array, $expected)) === 0);
foreach ($expected as $key => $value) {
if (is_array($value)) {
$this->assertArraySimilar($value, $array[$key]);
} else {
$this->assertContains($value, $array);
}
}
}
}
@AlexSkrypnyk
Copy link

In line 16, replace with $this->assertEquals([], array_diff_key($array, $expected)); in order to see which values are not similar.

@Stevemoretz
Copy link

Failed asserting that an array contains null.

Not working for nested arrays.

@keithbrink
Copy link

keithbrink commented Mar 3, 2022

Here's my take on this function:

public function assertArraysAreEqualIgnoringKeyOrder(array $expected, array $array)
{
    $this->assertEquals([], array_diff_key($expected, $array));
    $this->assertEquals([], array_diff_key($array, $expected));

    foreach ($expected as $key => $value) {
        if (is_array($value)) {
            $this->assertArraysAreEqualIgnoringKeyOrder($value, $array[$key]);
        } else {
            $this->assertEquals($value, $array[$key], "Array key '$key'");
        }
    }
}

EDIT: Of course, right after I post this I find out PHPUnit already supports this natively using assertEqualsCanonicalizing.

@colinmollenhour
Copy link

This version is an improvement in that it outputs the same array diff as assertSame() for easier debugging. Only ignores key order for first two levels, though.

    /**
     * Like assertSame but ignoring key order for first two levels.
     *
     * Asserts that two variables have the same type and value.
     * Used on objects, it asserts that two variables reference
     * the same object.
     *
     * @throws ExpectationFailedException
     *
     * @psalm-template ExpectedType
     * @psalm-param ExpectedType $expected
     * @psalm-assert =ExpectedType $actual
     */
    public function assertSameIgnoringKeyOrder(array $expected, array $array, string $message = null)
    {
        $same = TRUE;
        if (array_diff_key($expected, $array) || array_diff_key($array, $expected)) {
            $same = FALSE;
        } else {
            foreach ($expected as $key => $value) {
                if (is_array($value) && is_array($array[$key])) {
                    if (array_diff_key($value, $array[$key]) || array_diff_key($array[$key], $value)) {
                        $same = FALSE;
                        break;
                    }
                    foreach ($value as $_key => $_value) {
                        if ($_value !== $array[$key][$_key]) {
                            $same = FALSE;
                            break 2;
                        }
                    }
                } else {
                    if ($value !== $array[$key]) {
                        $same = FALSE;
                        break;
                    }
                }
            }
        }

        if ( ! $same) {
            if ($message) {
                $this->assertSame($expected, $array, $message);
            } else {
                $this->assertSame($expected, $array);
            }
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment