我只是想知道人们如何测试并断言“预期”集合与“实际”集合相同/相似(顺序并不重要)。
为了执行这个断言,我写了一个简单的断言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(..)。 / p>
我可以在这里使用一些测试库吗?你如何测试你的收藏?
感谢。
答案 0 :(得分:16)
我不确定您使用的是什么版本的JUnit,但最近的版本有一个assertThat
方法,它以Hamcrest Matcher为参数。它们是可组合的,因此您可以构建关于集合的复杂断言。
例如,如果你想断言集合A
包含集合B
中的每个元素,你可以写:
import static org.junit.Assert.*;
import static org.junit.matchers.JUnitMatchers.*;
import static org.hamcrest.core.IsCollectionContaining.*;
import static org.hamcrest.collection.IsCollectionWithSize.*;
import org.hamcrest.beans.SamePropertyValuesAs;
public class CollectionTests {
/*
* Tests that a contains every element in b (using the equals()
* method of each element) and that a has the same size as b.
*/
@Test
public void test() {
Collection<Foo> a = doSomething();
Collection<Foo> b = expectedAnswer;
assertThat(a, both(hasItems(b)).and(hasSize(b.size())));
}
/*
* Tests that a contains every element in b (using introspection
* to compare bean properties) and that a has the same size as b.
*/
@Test
public void testBeans() {
Collection<Foo> a = doSomething();
Collection<Foo> b = expectedAnswer;
Collection<Matcher<Foo>> bBeanMatchers =
new LinkedList<Matcher<Foo>>();
// create a matcher that checks for the property values of each Foo
for(Foo foo: B)
bBeanMatchers.add(new SamePropertyValuesAs(foo));
assertThat(a, both(hasItems(bBeanMatchers)).and(hasSize(b.size())))
}
}
第一个测试只是在每个对象上使用equalTo()匹配器(它将委托给你的equals实现)。如果这还不够强大,你可以使用第二种情况,它将使用getter和setter来比较每个元素。最后,您甚至可以编写自己的匹配器。 Hamcrest软件包没有匹配字段匹配(而不是匹配bean属性),但写一个FieldMatcher很简单(确实是一个很好的练习)。
Matchers一开始有点奇怪,但是如果你按照他们的例子来制作新的Matchers有一个返回匹配器的静态方法你可以做一堆import static
s你的代码基本上就像英文一样句子(“断言两者都有b中的项目并且与b具有相同的大小”)。你可以用这些东西建立一个非常令人印象深刻的DSL,让你的测试代码更加优雅。
答案 1 :(得分:8)
如果equals方法未检查所有字段,则可以使用Unitils http://unitils.org/ ReflectionAssert
类。调用
ReflectionAssert.assertReflectionEquals(expectedCollection,actualCollection)
将逐字段地反映每个元素(这不仅适用于集合,它适用于任何对象)。
答案 2 :(得分:1)
如果您尚未构建集合,则为另一种选择:
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.hamcrest.Matchers.is;
@Test
@SuppressWarnings("unchecked")
public void test_returnsList(){
arrange();
List<MyBean> myList = act();
assertThat(myList , contains(allOf(hasProperty("id", is(7L)),
hasProperty("name", is("testName1")),
hasProperty("description", is("testDesc1"))),
allOf(hasProperty("id", is(11L)),
hasProperty("name", is("testName2")),
hasProperty("description", is("testDesc2")))));
}
如果您不想检查对象的顺序,请使用containsInAnyOrder。
P.S。任何帮助以避免被禁止的警告将非常感激。
答案 3 :(得分:0)
我无法让jasonmp85's answer的最后一部分按原样运行。我包括了我使用的进口,因为为方便起见,一些junit罐包括旧的hamcrest东西。这对我有用,但断言循环肯定不如jason的答案中所写的那样好hasItems(..)
。
import org.hamcrest.Matcher;
import org.hamcrest.beans.SamePropertyValuesAs;
import org.hamcrest.collection.IsCollectionWithSize;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.MatcherAssert.assertThat;
...
/*
* Tests that a contains every element in b (using introspection
* to compare bean properties) and that a has the same size as b.
*/
@Test
public void testBeans() {
Collection<Foo> a = doSomething();
Collection<Foo> b = expectedAnswer;
Collection<Matcher<Foo>> bBeanMatchers = new LinkedList<Matcher<Foo>>();
// create a matcher that checks for the property values of each Foo
for(Foo foo: B)
bBeanMatchers.add(new SamePropertyValuesAs(foo));
// check that each matcher matches something in the list
for (Matcher<Foo> mf : bBeanMatchers)
assertThat(a, hasItem(mf));
// check that list sizes match
assertThat(a, IsCollectionWithSize.hasSize(b.size()));
}
...