我正在尝试使用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
实现:如果我必须使用反射手动编写代码来确定这一点,那么参数化测试的重点是什么?)
我的理解是参数化测试在每次测试之前调用构造函数,这应该干净地“重置”我的对象:为什么不是这种情况?
答案 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
。
答案 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)的