运行JUnit @Test方法的子集

我们使用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

我一直试图想办法用Javareflection等来实现这一点。因为似乎没有任何方法可以“隐藏” @Test方法或在运行时删除它们的注释,唯一的选择似乎是使用ClassLoader的defineClass方法,看起来相当困难。

PS在这种情况下,正确的事情是分割文件,但有其他选择吗?

谢谢你的时间。

从JUnit 4.8开始,我们有@Category注释来解决这个问题。

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构建文件中:

             

有关sysproperty标记的关键行。

而现在我可以跑了

 ant runtest -Dtest=MyTest -Dtests=testFoo,testBar 

如预期的。 这适用于JUnit 4.1 — 4.4,JUnit4ClassRunner的子类,以及4.5及更高版本的BlockJUnit4ClassRunner的子类。

创建自己的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”的测试。 其他人将被忽略:)只需将您的TestRunner类的@RunWith注释添加到您的测试中。

 @RunWith(FilteredTestRunner.class) public class ThisTestsWillNOTBeExecuted { //No test is executed. } @RunWith(FilteredTestRunner.class) public class ThisTestsWillBeExecuted { //All tests are executed. } 

createMethodRunner方法中,您可以根据必须执行的测试列表或引入新标准来检查当前测试。

祝你好运!

我们非常感谢提供更好的解决方案!

对于常见情况,有一种更简单的方法,您只需运行一种测试方法,而无需经历创建自定义RunnerFilter的麻烦:

 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. }