PHPUnit:断言两个数组相等,但元素的顺序不重要

2022-08-30 06:31:01

当数组中元素的顺序不重要,甚至可能会发生变化时,断言两个对象数组相等的好方法是什么?


答案 1

您可以使用 PHPUnit 7.5 中添加的 assertEqualsCanonicalization 方法。如果使用此方法比较数组,则这些数组将按 PHPUnit 数组比较器本身进行排序。

代码示例:

class ArraysTest extends \PHPUnit\Framework\TestCase
{
    public function testEquality()
    {
        $obj1 = $this->getObject(1);
        $obj2 = $this->getObject(2);
        $obj3 = $this->getObject(3);

        $array1 = [$obj1, $obj2, $obj3];
        $array2 = [$obj2, $obj1, $obj3];

        // Pass
        $this->assertEqualsCanonicalizing($array1, $array2);

        // Fail
        $this->assertEquals($array1, $array2);
    }

    private function getObject($value)
    {
        $result = new \stdClass();
        $result->property = $value;
        return $result;
    }
}

在较旧版本的 PHPUnit 中,您可以使用未记录的参数$canonicalize assertEquals 方法。如果传递$canonicalize = true,您将获得相同的效果:

class ArraysTest extends PHPUnit_Framework_TestCase
{
    public function testEquality()
    {
        $obj1 = $this->getObject(1);
        $obj2 = $this->getObject(2);
        $obj3 = $this->getObject(3);

        $array1 = [$obj1, $obj2, $obj3];
        $array2 = [$obj2, $obj1, $obj3];

        // Pass
        $this->assertEquals($array1, $array2, "\$canonicalize = true", 0.0, 10, true);

        // Fail
        $this->assertEquals($array1, $array2, "Default behaviour");
    }

    private function getObject($value)
    {
        $result = new stdclass();
        $result->property = $value;
        return $result;
    }
}

最新版本 PHPUnit 的数组比较器源代码:https://github.com/sebastianbergmann/comparator/blob/master/src/ArrayComparator.php#L46


答案 2

最干净的方法是使用新的断言方法扩展phpunit。但现在这里有一个更简单的方法的想法。未经测试的代码,请验证:

应用中的某个位置:

 /**
 * Determine if two associative arrays are similar
 *
 * Both arrays must have the same indexes with identical values
 * without respect to key ordering 
 * 
 * @param array $a
 * @param array $b
 * @return bool
 */
function arrays_are_similar($a, $b) {
  // if the indexes don't match, return immediately
  if (count(array_diff_assoc($a, $b))) {
    return false;
  }
  // we know that the indexes, but maybe not values, match.
  // compare the values between the two arrays
  foreach($a as $k => $v) {
    if ($v !== $b[$k]) {
      return false;
    }
  }
  // we have identical indexes, and no unequal values
  return true;
}

在测试中:

$this->assertTrue(arrays_are_similar($foo, $bar));

推荐