PHPUnit:断言两个数组相等,但元素的顺序并不重要
当数组中元素的顺序不重要甚至可能发生变化时,断言两个对象数组相等的好方法是什么?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
您可以使用 PHPUnit 7.5 中添加的 assertEqualsCanonicalizing 方法。如果使用此方法比较数组,这些数组将由 PHPUnit 数组比较器本身排序。
代码示例:
在旧版本的 PHPUnit 中,您可以使用 assertEquals 方法的未记录参数 $canonicalize。如果你传递$canonicalize = true,你会得到同样的效果:
最新版本PHPUnit的数组比较器源代码:https://github.com/sebastianbergmann/comparator/blob/master/src/ArrayComparator.php#L46
You can use assertEqualsCanonicalizing method 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.
Code example:
In older versions of PHPUnit you can use an undocumented param $canonicalize of assertEquals method. If you pass $canonicalize = true, you will get the same effect:
Arrays comparator source code at latest version of PHPUnit: https://github.com/sebastianbergmann/comparator/blob/master/src/ArrayComparator.php#L46
我的问题是我有 2 个数组(数组键与我无关,只与值相关)。
例如,我想测试是否
具有相同的内容(顺序与我无关),因此
我使用了 array_diff。
最终结果是(如果数组相等,则差异将导致空数组)。请注意,差异是通过两种方式计算的(感谢@beret,@GordonM)
对于更详细的错误消息(在调试时),您也可以像这样进行测试(感谢@DenilsonSá):
旧版本,内部有错误:
$ this->assertEmpty(array_diff($array2, $array1));My problem was that I had 2 arrays (array keys are not relevant for me, just the values).
For example I wanted to test if
had the same content (order not relevant for me) as
So I have used 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)
For a more detailed error message (while debugging), you can also test like this (thanks @DenilsonSá):
Old version with bugs inside:
$this->assertEmpty(array_diff($array2, $array1));最简洁的方法是使用新的断言方法来扩展 phpunit。但现在有一个更简单的方法的想法。未经测试的代码,请验证:
在您的应用程序中的某个位置:
在您的测试中:
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:
Somewhere in your app:
In your test:
另一种可能性:
One other possibility:
简单的辅助方法
或者如果您在数组不相等时需要更多调试信息
Simple helper method
Or if you need more debug info when arrays are not equal
如果密钥相同但顺序混乱,这应该可以解决问题。
您只需按相同顺序获取密钥并比较结果即可。
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.
即使您不关心顺序,考虑到这一点可能会更容易:
尝试:
Even though you do not care about the order, it might be easier to take that into account:
Try:
如果数组是可排序的,我会在检查相等性之前对它们进行排序。如果没有,我会将它们转换为某种类型的集合并进行比较。
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.
使用 array_diff():
或使用 2 个断言(更易于阅读):
Using array_diff():
Or with 2 asserts (easier to read):
我们在测试中使用以下包装方法:
We use the following wrapper method in our Tests:
给定的解决方案并不适合我,因为我希望能够处理多维数组并清楚地了解两个数组之间的差异。
这是我的函数
然后使用它
The given solutions didn't do the job for me because I wanted to be able to handle multi-dimensional array and to have a clear message of what is different between the two arrays.
Here is my function
Then to use it
我编写了一些简单的代码,首先从多维数组中获取所有键:
然后测试它们的结构是否相同,无论键的顺序如何:
HTH
I wrote some simple code to first get all the keys from a multi-dimensional array:
Then to test that they were structured the same regardless of the order of keys:
HTH
assertEqualsCanonicalizing()
的问题是,如果您要比较具有更复杂结构和更大深度的数组,则不能依赖它。最好的方法是使用
assertJsonStringEqualsJsonString
函数:优点:
免得看到详细解释:
在PhpStorm中查看差异的示例:
The problem with
assertEqualsCanonicalizing()
is that it can't be relied upon if you're comparing arrays with more complex structures and greater depth.The best approach is to use the
assertJsonStringEqualsJsonString
function:Benefits:
Lest see detailed explanation:
An example of viewing the difference in PhpStorm:
我正在转换为 json 并使用 Laravel assertJson():
I am converting to json and using Laravel assertJson():
如果值只是 int 或字符串,并且没有多级数组......
为什么不直接对数组进行排序,将它们转换为字符串......
然后比较字符串:
If values are just int or strings, and no multiple level arrays....
Why not just sorting the arrays, convert them to string...
... and then compare string:
如果您只想测试数组的值,您可以执行以下操作:
If you want test only the values of the array you can do:
另一种选择(就好像您还没有足够的一样)是将
assertArraySubset
与assertCount
结合起来进行断言。所以,你的代码看起来像这样。<代码>
self::assertCount(EXPECTED_NUM_ELEMENT, $array);
self::assertArraySubset(SUBSET, $array);
这样,您就可以独立于顺序,但仍然断言所有元素都存在。
Another option, as if you didn't already have enough, is to combine
assertArraySubset
combined withassertCount
to make your assertion. So, your code would look something like.self::assertCount(EXPECTED_NUM_ELEMENT, $array);
self::assertArraySubset(SUBSET, $array);
This way you are order independent but still assert that all your elements are present.