单元测试集合的最佳方法?
我只是想知道人们如何进行单元测试并断言“预期”集合与“实际”集合相同/相似(顺序并不重要)。
为了执行此断言,我编写了简单的断言 API:-
public void assertCollection(Collection<?> expectedCollection, Collection<?> actualCollection) {
assertNotNull(expectedCollection);
assertNotNull(actualCollection);
assertEquals(expectedCollection.size(), actualCollection.size());
assertTrue(expectedCollection.containsAll(actualCollection));
assertTrue(actualCollection.containsAll(expectedCollection));
}
嗯,它有效。如果我只断言一堆整数或字符串,那就非常简单了。例如,如果我试图断言 Hibernate 域的集合,这也可能会非常痛苦。 collection.containsAll(..) 依赖 equals(..) 来执行检查,但我总是覆盖 Hibernate 域中的 equals(..) 以仅检查业务键(这是Hibernate 网站)而不是该域的所有字段。当然,仅检查业务键是有意义的,但有时我真的想确保所有字段都正确,而不仅仅是业务键(例如,新的数据输入记录)。因此,在这种情况下,我不能乱用domain.equals(..),而且似乎我需要实现一些比较器只是出于单元测试的目的,而不是依赖collection.containsAll(..)。
我可以在这里利用一些测试库吗?您如何测试您的收藏?
谢谢。
I'm just wondering how folks unit test and assert that the "expected" collection is the same/similar as the "actual" collection (order is not important).
To perform this assertion, I wrote my simple assert API:-
public void assertCollection(Collection<?> expectedCollection, Collection<?> actualCollection) {
assertNotNull(expectedCollection);
assertNotNull(actualCollection);
assertEquals(expectedCollection.size(), actualCollection.size());
assertTrue(expectedCollection.containsAll(actualCollection));
assertTrue(actualCollection.containsAll(expectedCollection));
}
Well, it works. It's pretty simple if I'm asserting just bunch of Integers or Strings. It can also be pretty painful if I'm trying to assert a collection of Hibernate domains, say for example. The collection.containsAll(..) relies on the equals(..) to perform the check, but I always override the equals(..) in my Hibernate domains to check only the business keys (which is the best practice stated in the Hibernate website) and not all the fields of that domain. Sure, it makes sense to check just against the business keys, but there are times I really want to make sure all the fields are correct, not just the business keys (for example, new data entry record). So, in this case, I can't mess around with the domain.equals(..) and it almost seems like I need to implement some comparators for just unit testing purposes instead of relying on collection.containsAll(..).
Are there some testing libraries I could leverage here? How do you test your collection?
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不确定您使用的是哪个版本的 JUnit,但最近的 JUnit 有一个
assertThat
方法,该方法采用 Hamcrest Matcher 作为参数。它们是可组合的,因此您可以构建有关集合的复杂断言。例如,如果您想断言集合
A
包含集合B
中的每个元素,您可以编写:第一个测试仅在每个对象上使用 equalTo() 匹配器(这将委托给您的 equals 实现)。如果这还不够强大,您可以使用第二种情况,它将使用 getter 和 setter 来比较每个元素。最后,您甚至可以编写自己的匹配器。 Hamcrest 包没有提供用于按字段匹配的匹配器(而不是匹配 bean 属性),但编写 FieldMatcher 很简单(而且确实是一个很好的练习)。
匹配器一开始有点奇怪,但是如果您按照他们的示例制作新的匹配器,它有一个返回匹配器的静态方法,您可以执行一堆
import static
,您的代码基本上读起来就像英文句子(“断言 a 既具有 b 中的项,又与 b 的大小相同”)。您可以使用这些东西构建令人印象深刻的 DSL,并使您的测试代码更加优雅。I'm not sure what version of JUnit you're using, but recent ones have an
assertThat
method which takes a Hamcrest Matcher as an argument. They're composable so you can build up complex assertions about a collection.For instance, if you wanted to assert that a collection
A
contained every element in collectionB
, you could write:The first test just uses the equalTo() matcher on every object (which will delegate to your equals implementation). If that's not strong enough, you can use the second case, which will use getters and setters to compare every element. Finally, you can even write your own matchers. The Hamcrest package doesn't come with a matcher for matching by field (as opposed to matching bean properties), but it's trivial to write a FieldMatcher (and indeed is a good exercise).
The Matchers are a bit odd at first, but if you follow their example of making new Matchers have a static method that returns the matcher you can do a bunch of
import static
s and your code basically reads like an English sentence ("assert that a both has the items in b and has the same size as b"). You can build up a pretty impressive DSL with these things and make your test code a lot more elegant.如果 equals 方法没有检查所有字段,您可以使用 Unitils http://unitils.org/ <代码>ReflectionAssert类。调用
将逐个字段反射地比较每个元素(这不仅适用于集合,它适用于任何对象)。
If the equals method doesn't check all the fields, you can use the Unitils http://unitils.org/
ReflectionAssert
class. Callingwill compare each element reflectively field by field (and this doesn't just apply for collections, it will work for any object).
如果您还没有构建集合,则还有另一种选择:
使用 containsInAnyOrder 如果您不想检查对象的顺序。
PS 任何有助于避免被抑制的警告的帮助将不胜感激。
Another option if you have not build your collection:
Use containsInAnyOrder if you do not want to check the order of the objects.
P.S. Any help to avoid the warning that is suppresed will be really appreciated.
我无法让 jasonmp85 的答案 按原样工作。我包含了我使用的导入,因为一些 junit jars 包含旧的 hamcrest 东西以方便使用。这对我有用,但是断言循环绝对不如
hasItems(..)
就像杰森的答案中写的那样好。I couldn't get the last part of jasonmp85's answer to work as is. I included the imports I used because some junit jars include old hamcrest stuff for convenience. This works for me, but the assert loop definitely isn't as nice as if
hasItems(..)
worked as written in jason's answer.