参数化 jUnit 测试中的继承(或替代)
Inheritance (or an alternative) in Parameterized jUnit tests
我想在 jUnit 中做这样的事情:
@Runwith(Parameterized.class)
public abstract class BaseTest {
protected abstract List<Object[]> extraParams();
protected abstract ClassUnderTest testObject;
@Parameters
public Collection<Object[]> data() {
List<Object> params = ...; // a standard set of tests
params.addAll(extraParams());
return params;
}
@Test
public doTest() {
// assert things about testObject
}
}
public class ConcreteTest extends BaseTest {
protected ClassUnderTest = new ConcreteClass(...);
protected List<Object[]) extraParams() {
List<Object> extraParams = ...; // tests specific to this concrete type
return extraParams;
}
}
因此,通过扩展这个 class,我 运行 对被测对象进行了一系列标准测试,加上具体 class.[=14 中指定的一些额外测试=]
但是,jUnit 要求 @Parameters
方法是静态的。否则我怎么能整齐地达到目标,在具体的classes中有一组标准参数和额外的参数?
到目前为止我想出的最好办法是在摘要 class 中有一个未注释的 Collection<Object[]> standardParams()
,并要求 subclass 包含一个方法:
@Parameters
public Collection<Object[]> data() {
List<Object> params = standardParams();
params.addAll(...); // extra params
return params;
}
...但这并不像我想要的那样整洁,因为它给子 class.
的作者增加了太多责任
JUnit 要求 @Parameters 方法必须是静态的,如果您不提供静态方法,它会抛出 No public static parameters method on class Exception
.
但是您的要求可以通过如下实施org.junit.rules.TestRule来实现:
BaseTest class
public abstract class BaseTest {
@Rule
public MyBaseTestRule myProjectTestRule = new MyBaseTestRule(data());
protected abstract List<Object[]> extraParams();
public List<Object[]> data() {
List<Object[]> listTotal = new ArrayList<>();
listTotal.addAll(extraParams());
//add your base test data here
return listTotal;
}
public abstract List<Object[]> extraParams();
}
ConcreteTest class
public class ConcreteTest extends BaseTest {
@Override
public List<Object[]> extraParams() {
List<Object[]> list = ...//set up data here
return list;
}
@Test
public void test1() {
Object[] testData = myProjectTestRule.getTestData();
//use the test data for the test
//Example: Assume addition of two integers scenario and data
//data[0] expectedresult, data[1],[2] inputs
//Assert.assertEquals((int)data[0], (int)(data[1]+data[2]));
}
//add other test cases
}
MyBaseTestRule class:
import java.util.List;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class MyBaseTestRule implements TestRule {
private final List<Object[]> totalTestData;
private final int totalTestsSize;
private int currentTestIndex;
public MyProjectTestRule(List<Object[]> list) {
this.totalTestsSize = list.size();
this.totalTestData = list;
}
public Object[] getTestData(){
return totalTestData.get(currentTestIndex);
}
@Override
public Statement apply(Statement stmt, Description desc) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
for(int i=0; i<totalTestsSize; i++) {
currentTestIndex = i;
stmt.evaluate();
}
}
};
}
}
我想在 jUnit 中做这样的事情:
@Runwith(Parameterized.class)
public abstract class BaseTest {
protected abstract List<Object[]> extraParams();
protected abstract ClassUnderTest testObject;
@Parameters
public Collection<Object[]> data() {
List<Object> params = ...; // a standard set of tests
params.addAll(extraParams());
return params;
}
@Test
public doTest() {
// assert things about testObject
}
}
public class ConcreteTest extends BaseTest {
protected ClassUnderTest = new ConcreteClass(...);
protected List<Object[]) extraParams() {
List<Object> extraParams = ...; // tests specific to this concrete type
return extraParams;
}
}
因此,通过扩展这个 class,我 运行 对被测对象进行了一系列标准测试,加上具体 class.[=14 中指定的一些额外测试=]
但是,jUnit 要求 @Parameters
方法是静态的。否则我怎么能整齐地达到目标,在具体的classes中有一组标准参数和额外的参数?
到目前为止我想出的最好办法是在摘要 class 中有一个未注释的 Collection<Object[]> standardParams()
,并要求 subclass 包含一个方法:
@Parameters
public Collection<Object[]> data() {
List<Object> params = standardParams();
params.addAll(...); // extra params
return params;
}
...但这并不像我想要的那样整洁,因为它给子 class.
的作者增加了太多责任JUnit 要求 @Parameters 方法必须是静态的,如果您不提供静态方法,它会抛出 No public static parameters method on class Exception
.
但是您的要求可以通过如下实施org.junit.rules.TestRule来实现:
BaseTest class
public abstract class BaseTest {
@Rule
public MyBaseTestRule myProjectTestRule = new MyBaseTestRule(data());
protected abstract List<Object[]> extraParams();
public List<Object[]> data() {
List<Object[]> listTotal = new ArrayList<>();
listTotal.addAll(extraParams());
//add your base test data here
return listTotal;
}
public abstract List<Object[]> extraParams();
}
ConcreteTest class
public class ConcreteTest extends BaseTest {
@Override
public List<Object[]> extraParams() {
List<Object[]> list = ...//set up data here
return list;
}
@Test
public void test1() {
Object[] testData = myProjectTestRule.getTestData();
//use the test data for the test
//Example: Assume addition of two integers scenario and data
//data[0] expectedresult, data[1],[2] inputs
//Assert.assertEquals((int)data[0], (int)(data[1]+data[2]));
}
//add other test cases
}
MyBaseTestRule class:
import java.util.List;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class MyBaseTestRule implements TestRule {
private final List<Object[]> totalTestData;
private final int totalTestsSize;
private int currentTestIndex;
public MyProjectTestRule(List<Object[]> list) {
this.totalTestsSize = list.size();
this.totalTestData = list;
}
public Object[] getTestData(){
return totalTestData.get(currentTestIndex);
}
@Override
public Statement apply(Statement stmt, Description desc) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
for(int i=0; i<totalTestsSize; i++) {
currentTestIndex = i;
stmt.evaluate();
}
}
};
}
}