运行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
方法中,您可以根据必须执行的测试列表或引入新标准来检查当前测试。
祝你好运!
我们非常感谢提供更好的解决方案!
对于常见情况,有一种更简单的方法,您只需运行一种测试方法,而无需经历创建自定义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. }