java - 对集合进行单元测试的最佳方法?

标签 java unit-testing testing junit

我只是想知道人们如何进行单元测试并断言“预期”集合与“实际”集合相同/相似(顺序并不重要)。

为了执行这个断言,我编写了简单的断言 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(..) 以仅检查业务 key (这是在Hibernate 网站),而不是该域的所有字段。当然,只检查业务键是有意义的,但有时我真的想确保所有字段都正确,而不仅仅是业务键(例如,新的数据输入记录)。因此,在这种情况下,我不能乱用 domain.equals(..) 并且似乎我需要实现一些比较器来仅用于单元测试目的,而不是依赖于 collection.containsAll(..)。

我可以在这里利用一些测试库吗?您如何测试您的 Collection ?

谢谢。

最佳答案

我不确定您使用的是哪个版本的 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() 匹配器(它将委托(delegate)给您的 equals 实现)。如果这还不够强大,您可以使用第二种情况,它将使用 getter 和 setter 来比较每个元素。最后,您甚至可以编写自己的匹配器。 Hamcrest 包没有提供按字段匹配的匹配器(与匹配 bean 属性相反),但编写 FieldMatcher 很简单(确实是一个很好的练习)。

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

关于java - 对集合进行单元测试的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2922879/

相关文章:

java - 我的代码请求抛出异常,但是当我这样做时,它说不应抛出异常

java - 无法从 Web 服务方法的 try catch block 访问参数

java - 比较两个字符串给出 java.lang.NullPointerException

javascript - 测试功能组件内单击事件的函数/方法调用

c# - Visual Studio 2012 测试类别层次结构(测试资源管理器)

Java Reflect 2 对象

Android 单元测试 - 如何在与应用程序相同的项目中运行测试?

testing - Xcode 6 Beta 4 - 在测试目标中导入 swift 类

sql-server - 用于网站/Web 应用程序负载测试的工具?

javascript - enzyme 测试 : TypeError: expect(. ..).find 不是函数