Java 如何在JUnit4中动态创建测试套件?

Java 如何在JUnit4中动态创建测试套件?,java,junit,junit4,Java,Junit,Junit4,我想使用JUnit4创建一个junit测试套件,其中要包含的测试类的名称在测试套件运行之前是未知的 在JUnit 3中,我可以这样做: public final class MasterTester extends TestCase { /** * Used by junit to specify what TestCases to run. * * @return a suite containing what TestCases to run */ publ

我想使用JUnit4创建一个junit测试套件,其中要包含的测试类的名称在测试套件运行之前是未知的

在JUnit 3中,我可以这样做:

public final class MasterTester extends TestCase
{
  /**
   * Used by junit to specify what TestCases to run.
   * 
   * @return a suite containing what TestCases to run
   */
  public static TestSuite suite() {
    TestSuite suite = new TestSuite();

    for(Class<?> klass : gatherTestClasses()) {
      suite.addTestSuite(klass);
    }

    return suite;
  }
}
公共最终类MasterTester扩展了测试用例
{
/**
*junit用于指定要运行的测试用例。
* 
*@返回包含要运行的测试用例的套件
*/
公共静态测试套件(){
TestSuite=新的TestSuite();
对于(类klass:gatherTestClasses()){
suite.addTestSuite(klass);
}
返回套房;
}
}
然后让
gatherTestClasses()
方法计算要运行的测试类

在JUnit4中,声明使用注释:
@SuiteClasses({TestClass1.class,TestClass2.class…})
来构建我的测试套件。这里有一些演示如何做到这一点。不幸的是,我看到的示例似乎不允许传递动态生成的TestClass列表

这意味着我必须对
BlockJUnit4ClassRunner
进行子类化,我不想这样做


动态指定的测试套件似乎必须在JUnit4中的某个地方。有人知道在哪里吗?

我不确定gatherTestClasses()做什么,但假设它在操作系统为Linux时返回一些测试,在操作系统为Windows时返回不同的测试。您可以在JUnit 4.4中通过以下方式复制:


getOS()
OperatingSystem
的实现是您的自定义代码。

我发现类路径套件与测试类的命名约定一起使用时非常有用

以下是一个例子:

import org.junit.extensions.cpsuite.ClasspathSuite;
import org.junit.runner.RunWith;

@RunWith(ClasspathSuite.class)
@ClassnameFilters({".*UnitTest"})
public class MySuite {
}

要创建动态测试套件,需要使用
@RunWith
注释。有两种常用的使用方法:

@RunWith(Suite.class)

这允许您指定哪些类构成了有问题的测试套件。这相当于JUnit 3样式:

import junit.framework.TestSuite;
import junit.framework.TestCase;

public final class MasterTester extends TestCase {

  public static TestSuite suite() {
    TestSuite suite = new TestSuite();
    suite.addTestSuite(TestClass1.class);        
    suite.addTestSuite(TestClass2.class);
    // etc...
    return suite;
  }
}
等效的JUnit 4类将是:

import org.junit.runners.Suite;

@RunWith(Suite.class)
@SuiteClasses({TestClass1.class, TestClass2.class})
public final class MasterTester {

}
@RunWith(AllTests.class)

这允许您动态指定组成测试套件的测试。如果直到运行时才知道测试,则不能在注释中指定它们。您可以改为使用此结构。因此,如果JUnit 3代码是:

import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.framework.Test;

public final class MasterTester extends TestCase {

  public static TestSuite suite() {
    TestSuite suite = new TestSuite();
    for (Test test : findAllTestCasesRuntime()) {
      suite.addTest(test);
    }
    return suite;
  }
}
等效的JUnit 4代码为:

import org.junit.runners.AllTests;
import junit.framework.TestSuite;
import junit.framework.Test;

@RunWith(AllTests.class)
public final class MasterTester {

  public static TestSuite suite() {
    TestSuite suite = new TestSuite();
    for (Test test : findAllTestCasesRuntime()) {
      suite.addTest(test);
    }
    return suite;
  }
}

我已经使用JUnit 4.8尝试过这一点,它可以工作:

@RunWith(AllTests.class)
public class SomeTests
{
    public static TestSuite suite()
    {
        TestSuite suite = new TestSuite();

        suite.addTest(new JUnit4TestAdapter(Test1.class));
        suite.addTest(new JUnit4TestAdapter(Test2.class));

        return suite;
     }
}

下面是一个完整的示例,说明如何实现这一点。它由两个测试用例类和一个套件组成

  • 示例仪表测试:

    import android.support.test.rule.ActivityTestRule;
    
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.JUnit4;
    
    @RunWith(JUnit4.class)
    public class ExampleInstrumentedTest {
    
    
        @Rule
        public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);
    
        @Test
        public void checkInputs() throws Exception {
    
        }
    }
    
    import android.support.test.rule.ActivityTestRule;
    
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.JUnit4;
    
    @RunWith(JUnit4.class)
    public class ExampleInstrumentedTest2 {
    
    
        @Rule
        public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);
    
        @Test
        public void checkInputs() throws Exception {
    
        }
    }
    
    import junit.framework.TestSuite;
    
    import org.junit.runner.RunWith;
    import org.junit.runners.AllTests;
    
    @RunWith(AllTests.class)
    public class ExampleInstrumentedSuite {
    
        public static TestSuite suite() {
            TestSuite suite = new TestSuite();
            suite.addTest(new junit.framework.JUnit4TestAdapter(ExampleInstrumentedTest.class));
            suite.addTest(new junit.framework.JUnit4TestAdapter(ExampleInstrumentedTest2.class));
            return suite;
        }
    }
    
  • 注意,您应该在testCase类中使用
    @RunWith(JUnit4.class)
    而不是默认的
    @RunWith(AndroidJUnit4.class)
    {
    public class MyTestCase extends TestCase {
        @Override
        public void runTest() {
            // define assertion here  <===
            assertEquals("yes", "yes");
        }
    }
    
    @RunWith(AllTests.class)
    public class DynamicTestSuite {
        public static TestSuite suite() {
            TestSuite suite = new TestSuite();
    
            // dynamically create your test case here  <====
            suite.addTest(new MyTestCase());
    
            return suite;
        }
    }
    
    @凌驾 公共无效运行测试(){
    //在这里定义断言完美,正是我想要的。如果你使用的是apache commons lang,你可以使用“assumeTrue(SystemUtils.IS_OS_WINDOWS)”,这个for循环中的操作似乎是错误的。你的意思是做suite.addTest(test);?@Danail Nachev:对不起,这完全没有意义(不是你的错).JUnit4自豪地将继承替换为注释,因此我没有任何
    测试
    ,只有普通的旧类。因此,除非我全部编辑它们,否则您的解决方案对我不起作用。如何实现findAllTestCasesRuntime()方法?您可以使用
    junit.framework.JUnit4TestAdapter
    构造一个合适的对象来表示您的测试类。但是方法
    findAllTestCasesRuntime()在哪里
    ?如果没有这一点,列表是不完整的。Andrejs的回答使类路径变得多余,至少对于动态创建测试套件的任务来说是如此。看起来它不再被维护,并且与本机库有很多问题,我用这个方法该怎么办?我希望该套件成为我父套件的子套件我尝试过,但是如果我添加
    @BeforeClass
    注释它,则
    @BeforeClass
    中的代码不起作用。知道吗?
    JUnit4TestAdapter
    做什么?@Arik
    所有测试
    运行者不喜欢
    @BeforeClass
    。使用
    public class MyTestCase extends TestCase {
        @Override
        public void runTest() {
            // define assertion here  <===
            assertEquals("yes", "yes");
        }
    }
    
    @RunWith(AllTests.class)
    public class DynamicTestSuite {
        public static TestSuite suite() {
            TestSuite suite = new TestSuite();
    
            // dynamically create your test case here  <====
            suite.addTest(new MyTestCase());
    
            return suite;
        }
    }