php PHPUnit:断言两个数组相等,但元素顺序不重要
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3838288/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHPUnit: assert two arrays are equal, but order of elements not important
提问by koen
What is a good way to assert that two arrays of objects are equal, when the order of the elements in the array is unimportant, or even subject to change?
当数组中元素的顺序不重要,甚至可能会发生变化时,断言两个对象数组相等的好方法是什么?
采纳答案by Craig
The cleanest way to do this would be to extend phpunit with a new assertion method. But here's an idea for a simpler way for now. Untested code, please verify:
最简洁的方法是使用新的断言方法扩展 phpunit。但现在这里有一个更简单的方法的想法。未经测试的代码,请验证:
Somewhere in your app:
在您的应用程序中的某处:
/**
* 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;
}
In your test:
在您的测试中:
$this->assertTrue(arrays_are_similar($foo, $bar));
回答by pryazhnikov
You can use assertEqualsCanonicalizingmethod which was added in PHPUnit 7.5. If you compare the arrays using this method, these arrays will be sorted by PHPUnit arrays comparator itself.
您可以使用PHPUnit 7.5 中添加的assertEqualsCanonicalizing方法。如果您使用此方法比较数组,这些数组将按 PHPUnit 数组比较器本身排序。
Code example:
代码示例:
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;
}
}
In older versions of PHPUnit you can use an undocumented param $canonicalize of assertEqualsmethod. If you pass $canonicalize = true, you will get the same effect:
在旧版本的 PHPUnit 中,您可以使用assertEquals方法的未公开参数 $canonicalize 。如果您通过$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;
}
}
Arrays comparator source code at latest version of PHPUnit: https://github.com/sebastianbergmann/comparator/blob/master/src/ArrayComparator.php#L46
最新版 PHPUnit 的数组比较器源代码:https: //github.com/sebastianbergmann/comparator/blob/master/src/ArrayComparator.php#L46
回答by Valentin Despa
My problem was that I had 2 arrays (array keys are not relevant for me, just the values).
我的问题是我有 2 个数组(数组键与我无关,只是值)。
For example I wanted to test if
例如我想测试是否
$expected = array("0" => "green", "2" => "red", "5" => "blue", "9" => "pink");
had the same content (order not relevant for me) as
具有与我相同的内容(订单与我无关)
$actual = array("0" => "pink", "1" => "green", "3" => "yellow", "red", "blue");
So I have used array_diff.
所以我使用了array_diff。
Final result was (if the arrays are equal, the difference will result in an empty array). Please note that the difference is computed both ways (Thanks @beret, @GordonM)
最终结果是(如果数组相等,则差异将导致一个空数组)。请注意,差异是双向计算的(感谢@beret、@GordonM)
$this->assertEmpty(array_merge(array_diff($expected, $actual), array_diff($actual, $expected)));
For a more detailed error message (while debugging), you can also test like this (thanks @DenilsonSá):
有关更详细的错误消息(调试时),您还可以这样测试(感谢@DenilsonSá):
$this->assertSame(array_diff($expected, $actual), array_diff($actual, $expected));
Old version with bugs inside:
旧版本,内部有错误:
$this->assertEmpty(array_diff($array2, $array1));
$this->assertEmpty(array_diff($array2, $array1));
回答by rodrigo-silveira
One other possibility:
另一种可能:
- Sort both arrays
- Convert them to a string
- Assert both strings are equal
- 对两个数组进行排序
- 将它们转换为字符串
- 断言两个字符串相等
$arr = array(23, 42, 108);
$exp = array(42, 23, 108);
sort($arr);
sort($exp);
$this->assertEquals(json_encode($exp), json_encode($arr));
回答by ksimka
Simple helper method
简单的辅助方法
protected function assertEqualsArrays($expected, $actual, $message) {
$this->assertTrue(count($expected) == count(array_intersect($expected, $actual)), $message);
}
Or if you need more debug info when arrays are not equal
或者,如果您在数组不相等时需要更多调试信息
protected function assertEqualsArrays($expected, $actual, $message) {
sort($expected);
sort($actual);
$this->assertEquals($expected, $actual, $message);
}
回答by Rodney Gitzel
If the array is sortable, I would sort them both before checking equality. If not, I would convert them to sets of some sort and compare those.
如果数组是可排序的,我会在检查相等性之前对它们进行排序。如果没有,我会将它们转换为某种集合并进行比较。
回答by caligari
Using array_diff():
使用array_diff():
$a1 = array(1, 2, 3);
$a2 = array(3, 2, 1);
// error when arrays don't have the same elements (order doesn't matter):
$this->assertEquals(0, count(array_diff($a1, $a2)) + count(array_diff($a2, $a1)));
Or with 2 asserts (easier to read):
或者使用 2 个断言(更容易阅读):
// error when arrays don't have the same elements (order doesn't matter):
$this->assertEquals(0, count(array_diff($a1, $a2)));
$this->assertEquals(0, count(array_diff($a2, $a1)));
回答by Antonis Charalambous
Even though you do not care about the order, it might be easier to take that into account:
即使您不关心顺序,考虑到这一点可能会更容易:
Try:
尝试:
asort($foo);
asort($bar);
$this->assertEquals($foo, $bar);
回答by Cris
If the keys are the same but out of order this should solve it.
如果键相同但乱序,这应该可以解决它。
You just have to get the keys in the same order and compare the results.
您只需按照相同的顺序获取密钥并比较结果。
/**
* Assert Array structures are the same
*
* @param array $expected Expected Array
* @param array $actual Actual Array
* @param string|null $msg Message to output on failure
*
* @return bool
*/
public function assertArrayStructure($expected, $actual, $msg = '') {
ksort($expected);
ksort($actual);
$this->assertSame($expected, $actual, $msg);
}
回答by t.heintz
We use the following wrapper method in our Tests:
我们在测试中使用以下包装方法:
/**
* Assert that two arrays are equal. This helper method will sort the two arrays before comparing them if
* necessary. This only works for one-dimensional arrays, if you need multi-dimension support, you will
* have to iterate through the dimensions yourself.
* @param array $expected the expected array
* @param array $actual the actual array
* @param bool $regard_order whether or not array elements may appear in any order, default is false
* @param bool $check_keys whether or not to check the keys in an associative array
*/
protected function assertArraysEqual(array $expected, array $actual, $regard_order = false, $check_keys = true) {
// check length first
$this->assertEquals(count($expected), count($actual), 'Failed to assert that two arrays have the same length.');
// sort arrays if order is irrelevant
if (!$regard_order) {
if ($check_keys) {
$this->assertTrue(ksort($expected), 'Failed to sort array.');
$this->assertTrue(ksort($actual), 'Failed to sort array.');
} else {
$this->assertTrue(sort($expected), 'Failed to sort array.');
$this->assertTrue(sort($actual), 'Failed to sort array.');
}
}
$this->assertEquals($expected, $actual);
}