我们正在使用JUnit 4进行测试:我们的类不是TestCase
的子类,并且它们具有使用@Test
注释的公共方法。我们有一个文件包含许多@Test
方法。能够通过命令行中的Ant运行它们的子集会很好,这是JUnit 3的这个配方样式:
ant runtest -Dtest=MyTest -Dtests=testFoo,testBar
http://today.java.net/pub/a/today/2003/09/12/individual-test-cases.html
我一直在想办法用Java反射等来实现这个目标。因为似乎没有办法在运行时“隐藏”@Test
方法或删除它们的注释,所以选项似乎是使用ClassLoader的defineClass
方法,这似乎很难。
P.S。在这种情况下,正确的事情是分割文件,但有其他选择吗?
感谢您的时间。
答案 0 :(得分:13)
从JUnit 4.8开始,我们有@Category注释来解决这个问题。
答案 1 :(得分:10)
guerda的解决方案很好。这就是我最终做的事情(这是我之前联系过的Luke Francl的配方,以及我在网上看到的其他一些东西):
import org.junit.runner.manipulation.Filter;
import org.junit.runner.Description;
public final class AntCLFilter extends Filter {
private static final String TEST_CASES = "tests";
private static final String ANT_PROPERTY = "${tests}";
private static final String DELIMITER = "\\,";
private String[] testCaseNames;
public AntCLFilter() {
super();
if (hasTestCases()) testCaseNames = getTestCaseNames();
}
public String describe() {
return "Filters out all tests not explicitly named in a comma-delimited list in the system property 'tests'.";
}
public boolean shouldRun(Description d) {
String displayName = d.getDisplayName();
// cut off the method name:
String testName = displayName.substring(0, displayName.indexOf('('));
if (testCaseNames == null) return true;
for (int i = 0; i < testCaseNames.length; i++)
if (testName.equals(testCaseNames[i]))
return true;
return false;
}
/**
* Check to see if the test cases property is set. Ignores Ant's
* default setting for the property (or null to be on the safe side).
**/
public static boolean hasTestCases() {
return
System.getProperty( TEST_CASES ) == null ||
System.getProperty( TEST_CASES ).equals( ANT_PROPERTY ) ?
false : true;
}
/**
* Create a List of String names of test cases specified in the
* JVM property in comma-separated format.
*
* @return a List of String test case names
*
* @throws NullPointerException if the TEST_CASES property
* isn't set
**/
private static String[] getTestCaseNames() {
if ( System.getProperty( TEST_CASES ) == null ) {
throw new NullPointerException( "Test case property is not set" );
}
String testCases = System.getProperty( TEST_CASES );
String[] cases = testCases.split(DELIMITER);
return cases;
}
}
import org.junit.internal.runners.*;
import org.junit.runner.manipulation.Filter;
import org.junit.runner.manipulation.NoTestsRemainException;
public class FilteredRunner extends TestClassRunner {
public FilteredRunner(Class<?> clazz) throws InitializationError {
super(clazz);
Filter f = new AntCLFilter();
try {
f.apply(this);
} catch (NoTestsRemainException ex) {
throw new RuntimeException(ex);
}
}
}
然后我用:
注释我的测试类@RunWith(FilteredRunner.class)
public class MyTest {
并将以下内容放在我的ant buildfile中:
<target name="runtest"
description="Runs the test you specify on the command line with -Dtest="
depends="compile, ensure-test-name">
<junit printsummary="withOutAndErr" fork="yes">
<sysproperty key="tests" value="${tests}" />
<classpath refid="classpath" />
<formatter type="plain" usefile="false" />
<batchtest>
<fileset dir="${src}">
<include name="**/${test}.java" />
</fileset>
</batchtest>
</junit>
</target>
存在sysproperty标记的关键行。
现在我可以运行
了ant runtest -Dtest=MyTest -Dtests=testFoo,testBar
根据需要。这适用于JUnit 4.1 --- 4.4,JUnit4ClassRunner的子类,以及4.5及更高版本的BlockJUnit4ClassRunner的子类。
答案 2 :(得分:8)
创建自己的TestClassMethodsRunner
(它没有记录,或者我现在没有找到它)
TestClassMethodsRunner
执行所有TestCase,您可以设置已过滤的TestClassMethodsRunner
。
您所要做的就是覆盖TestMethodRunner createMethodRunner(Object, Method, RunNotifier)
方法。这是一个简单的hacky解决方案:
public class FilteredTestRunner extends TestClassMethodsRunner {
public FilteredTestRunner(Class<?> aClass) {
super(aClass);
}
@Override
protected TestMethodRunner createMethodRunner(Object aTest, Method aMethod, RunNotifier aNotifier) {
if (aTest.getClass().getName().contains("NOT")) {
return new TestMethodRunner(aTest, aMethod, aNotifier, null) {
@Override
public void run() {
//do nothing with this test.
}
};
} else {
return super.createMethodRunner(aTest, aMethod, aNotifier);
}
}
}
使用此TestRunner,您可以执行所有不包含字符串“NOT”的测试。其他人将被忽略:)只需将@RunWith
注释与TestRunner类一起添加到测试中。
@RunWith(FilteredTestRunner.class)
public class ThisTestsWillNOTBeExecuted {
//No test is executed.
}
@RunWith(FilteredTestRunner.class)
public class ThisTestsWillBeExecuted {
//All tests are executed.
}
在createMethodRunner
方法中,您可以根据必须执行的测试列表或引入新标准来检查当前测试。
祝你好运!
赞赏一个更好的解决方案的提示!
答案 3 :(得分:1)
对于常见情况,有一种更简单的方法,您只需要运行一种测试方法,而无需经历创建自定义Runner
或Filter
的麻烦:
public class MyTestClass {
public static void main(final String[] args) throws Exception {
final JUnitCore junit = new JUnitCore();
final String singleTest = // Get the name of test from somewhere (environment, system property, whatever you want).
final Request req;
if (singleTest != null) {
req = Request.method(MyTestClass.class, singleTest);
} else {
req = Request.aClass(MyTestClass.class);
}
final Result result = junit.run(req);
// Check result.getFailures etc.
if (!result.wasSuccessful()) {
System.exit(1);
}
}
// Your @Test methods here.
}