JUnit测试:在参数化测试之间不重新创建对象

时间:2014-01-20 07:12:38

标签: java unit-testing junit

我正在尝试使用JUnit4 Collections测试来测试Parameterized接口的实现。我的测试类有两个测试:

@RunWith(Parameterized.class)
public class CollectionsTest {

    private Collection<String> col;
    private Collection<String> other;

    public CollectionsTest(Collection<String> c, Collection<String> other) {
        this.col = c;
        this.other = other;
    }

    @Parameterized.Parameters
    public static java.util.Collection<Object[]> tokenStreams() {
        return (java.util.Collection<Object[]>) Arrays.asList(new Object[][] { 
            { new DSLinkedList<String>(), new DSLinkedList<String>() } });
    }

    @Test
    public final void isEmpty() {
        assertTrue(col.getClass().getName() + ".isEmpty() should return true when collection contains no elements", col.isEmpty()); 
        col.add("Stringthing");
        assertFalse(col.getClass().getName() + ".isEmpty() should return false when collection contains elements", col.isEmpty());
    }

    @Test
    public final void size() {
        assertEquals(col.getClass().getName() + ".size() should be 0 for an empty collection.", 0, col.size());
        col.add("String");
        assertEquals(col.getClass().getName() + ".size() should be 1 for a collection with one element.", 1, col.size());       
    }
}

第二个测试(size())总是失败:在第一个断言时,col包含单个元素stringThing,因为我在{{1}中插入了一个元素测试。

如何在测试之间清理参数化对象?

如果我没有使用参数化测试,我会使用isEmpty() @Before方法:我应该在这里使用反射和设置方法重新创建setup()col个对象? (我没有这样做,因为我不知道每个测试预先运行了哪个other实现:如果我必须使用反射手动编写代码来确定这一点,那么参数化测试的重点是什么?)

我的理解是参数化测试在每次测试之前调用构造函数,这应该干净地“重置”我的对象:为什么不是这种情况?

4 个答案:

答案 0 :(得分:1)

Parameterized在每次测试之前创建一个新的CollectionsTest对象并调用构造函数,但每次都传递相同的DSLinkedList对象,对整个测试用例只调用一次tokenStreams()。您应该自己清理构造函数中的列表。

答案 1 :(得分:1)

Java 8 中,可以使用 lambda表达式和实用程序类java.util.function.Supplier相当干净地完成此操作。您不必提供参数类型的实例,而是提供一个lambda,每次评估时都会提供一个新实例。 JUnit将lambda传递给每个测试用例的构造函数,其中通过调用get()创建一个新实例。

@RunWith(Parameterized.class)
public class CollectionsTest {

  private Collection<String> col;
  private Collection<String> other;

  public CollectionsTest(Supplier<Collection<String>> c, Supplier<Collection<String>> other) {
    this.col = c.get();
    this.other = other.get();
}

@Parameterized.Parameters
public static java.util.Collection<Object[]> tokenStreams() {
    Supplier<Collection<String>> c1 = () -> new DSLinkedList<String>();
    Supplier<Collection<String>> c2 = () -> new DSLinkedList<String>();

    return Arrays.asList(new Object[][] { { c1, c2 } });
}

@Test
public final void isEmpty() {
    assertTrue(col.getClass().getName() + ".isEmpty() should return true when collection contains no elements", col.isEmpty()); 
    col.add("Stringthing");
    assertFalse(col.getClass().getName() + ".isEmpty() should return false when collection contains elements", col.isEmpty());
}

@Test
public final void size() {
    assertEquals(col.getClass().getName() + ".size() should be 0 for an empty collection.", 0, col.size());
    col.add("String");
    assertEquals(col.getClass().getName() + ".size() should be 1 for a collection with one element.", 1, col.size());       
}

答案 2 :(得分:0)

嗯,您正在更改成员变量值。那么,您是否期望在每次测试之前调用构造函数?另外,根据参数化的文档。您的测试类instance将在@Parameters方法中提供数据值。它不是每个测试都是类的instance

Parameterized

答案 3 :(得分:0)

这是一个迟到的回应。但我遇到了同样的困境,我解决了这个问题:

@RunWith(Parameterized.class)
public class CollectionsTest {

    private Collection<String> col;
    private Collection<String> other;

    private Class<Collection> source1;
    private Class<Collection> source2;

    public CollectionsTest(Class<Collection> first, Class<Collection> second) {
        this.source1 = first;
        this.source2 = second;
    }

    @Parameters
    public static Collection<Object[]> instancesToTest() {
        return Arrays.asList(new Object[][] { 
                { DSLinkedList.class, DSLinkedList.class }, 
                { OtherCollection.class, MyCollection.class } 
        });
    }

    @Before
    public void setUp() throws Exception {
        this.col = source1.newInstance();
        this.other = source2.newInstance();
    }

    . . .

只要您的类具有默认构造函数(无参数),此方法就可以工作 在每次测试之前调用@Before setup()方法,并为对象创建一个新实例。

要使用非默认构造函数,您可以使用getConstructor()来选择所需的构造函数:

this.col = source1.getConstructor(String.class).newInstance("Hello object");

您也可以使用相同的技术(例如Collection<String> c1 = source1.newInstance())在测试中创建新对象,这些测试必须抛出Exception(如果他们不这样做,您将收到编译时错误#39} ; t)的