单元测试集合的最佳方式?

lim*_*imc 23 java testing junit unit-testing

我只是想知道人们如何测试并断言"预期"集合与"实际"集合相同/相似(顺序并不重要).

为了执行这个断言,我编写了我的简单断言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));
}
Run Code Online (Sandbox Code Playgroud)

嗯,它的工作原理.如果我断言只是一堆整数或字符串,这很简单.例如,如果我试图断言Hibernate域的集合,那也可能会非常痛苦.collection.containsAll(..)依赖于equals(..)来执行检查,但我总是覆盖我的Hibernate域中的equals(..)以仅检查业务键(这是最好的做法,在Hibernate网站)而不是该域的所有字段.当然,检查业务键是有意义的,但有时我真的想确保所有字段都正确,而不仅仅是业务键(例如,新的数据输入记录).所以,在这种情况下,我无法搞乱domain.equals(..

我可以在这里使用一些测试库吗?你如何测试你的收藏?

谢谢.

jas*_*p85 17

我不确定你正在使用什么版本的JUnit,但是最近的版本有一个assertThatHamcrest 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())))
    }
}
Run Code Online (Sandbox Code Playgroud)

第一个测试只是在每个对象上使用equalTo()匹配器(它将委托给你的equals实现).如果这还不够强大,你可以使用第二种情况,它将使用getter和setter来比较每个元素.最后,您甚至可以编写自己的匹配器.Hamcrest包没有匹配字段匹配(而不是匹配bean属性),但编写FieldMatcher很简单(确实是一个很好的练习).

Matchers一开始有点奇怪,但如果你按照他们的例子来制作新的Matchers有一个静态方法返回匹配器你可以做一堆import statics,你的代码基本上读起来就像一个英语句子("断言两者都有b中的项目与b")具有相同的大小.您可以使用这些东西构建一个非常令人印象深刻的DSL,并使您的测试代码更加优雅.

  • @ jasonmp85这段代码对你有用吗?我得到`和(org.hamcrest.Matcher <?super java.lang.Iterable <java.util.Collection <org.hamcrest.Matcher <org.bitbucket.artbugorski.brainfuj.interpreter.InterpreterTest.Foo >>>> )使用Hamcrest 1.2无法将CombinableMatcher应用于(org.hamcrest.Matcher <capture <?super java.util.Collection <?extends java.lang.Object >>>)` (5认同)

Jef*_*rey 8

如果equals方法不检查所有字段,则可以使用Unitils http://unitils.org/ ReflectionAssert类.调用

ReflectionAssert.assertReflectionEquals(expectedCollection,actualCollection)
Run Code Online (Sandbox Code Playgroud)

将逐个字段地反复比较每个元素(这不仅适用于集合,它将适用于任何对象).