如何在 JUnit 4 中动态创建测试套件?

发布于 2024-09-10 05:18:44 字数 1150 浏览 4 评论 0原文

我想使用 JUnit 4 创建一个 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;
  }
}

并让 GatherTestClasses() 方法来确定要运行哪些测试类。

在 JUnit 4 中,文档 表示使用注释:@SuiteClasses( {TestClass1.class, TestClass2.class...}) 来构建我的测试套件。有许多答案展示了如何做这个。不幸的是,我看到的示例似乎不允许传递动态生成的 TestClasses 列表。

这个所以答案 建议我必须对 BlockJUnit4ClassRunner 进行子类化,但我不想这样做。

动态指定的测试套件似乎必须存在于 JUnit 4 的某个地方。有谁知道在哪里吗?

I would like to create a junit test suite using JUnit 4 where the names of the test classes to be included are not known until the test suite is run.

In JUnit 3 I could do this:

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

and let the gatherTestClasses() method deal with figuring out what test classes to run.

In JUnit 4, the documentation says to use an annotation: @SuiteClasses({TestClass1.class, TestClass2.class...}) to build up my test suite. There are numerous SO answers showing how to do this. Unfortunately the examples I see do not seem to allow for passing a dynamically generated list of TestClasses.

This SO answer suggested I would have to subclass BlockJUnit4ClassRunner which I do not want to do.

Dynamically specified test suites seem like something that must be in JUnit 4 somewhere. Does anyone know where?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

泅渡 2024-09-17 05:18:44

要创建动态测试套件,您需要使用@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;
  }
}

To create a dynamic test suite, you need to use the @RunWith annotation. There are two common ways to use it:

@RunWith(Suite.class)

This allows you to specify, which classes compose the test suite in question. This is equivalent to the JUnit 3 style:

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

The equivalent JUnit 4 class will be:

import org.junit.runners.Suite;

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

}

@RunWith(AllTests.class)

This allows you to dynamically specify the tests, which compose the test suite. If your tests are not known until runtime, you cannot specify them in the annotations. You can use this construction instead. So, if the JUnit 3 code is:

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

The equivalent JUnit 4 code will be:

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;
  }
}
横笛休吹塞上声 2024-09-17 05:18:44

我已经使用 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;
     }
}

I've tried this using JUnit 4.8 and it works:

@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;
     }
}
野鹿林 2024-09-17 05:18:44

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

https://github.com/takari/takari-cpsuite

这是一个示例:

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

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

I found Classpath suite quite useful when used with a naming convention on my test classes.

https://github.com/takari/takari-cpsuite

Here is an example:

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

@RunWith(ClasspathSuite.class)
@ClassnameFilters({".*UnitTest"})
public class MySuite {
}
网白 2024-09-17 05:18:44

我不确定 GatherTestClasses() 的作用,但假设它在操作系统为 Linux 时返回一些测试,在操作系统为 Windows 时返回不同的测试。您可以使用 假设 在 JUnit 4.4 中复制这一点:

@Test
public void onlyOnLinux() {
    assumeThat(getOS(), is(OperatingSystem.LINUX));
    // rest of test
}

@Test
public void onlyOnWindows() {
    assumeThat(getOS(), is(OperatingSystem.WINDOWS));
    // rest of test
}

@Test
public void anyOperatingSystem() {
    // just don't call assumeThat(..)
}

< code>getOS() 和 OperatingSystem 是您的自定义代码。

I'm not sure what gatherTestClasses() does, but let's say it returns some tests when the OS is Linux and different tests when the OS is Windows. You can replicate that in JUnit 4.4 with assumptions:

@Test
public void onlyOnLinux() {
    assumeThat(getOS(), is(OperatingSystem.LINUX));
    // rest of test
}

@Test
public void onlyOnWindows() {
    assumeThat(getOS(), is(OperatingSystem.WINDOWS));
    // rest of test
}

@Test
public void anyOperatingSystem() {
    // just don't call assumeThat(..)
}

The implementation of getOS() and OperatingSystem being your custom code.

夏见 2024-09-17 05:18:44

这是一个如何实现它的完整示例。它结合了两个测试用例类和一个套件。

  1. 示例仪器测试:

    导入 android.support.test.rule.ActivityTestRule;
    
    导入 org.junit.Rule;
    导入 org.junit.Test;
    导入 org.junit.runner.RunWith;
    导入 org.junit.runners.JUnit4;
    
    @RunWith(JUnit4.class)
    公共类ExampleInstrumentedTest {
    
    
        @规则
        公共 ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class);
    
        @测试
        公共无效checkInputs()抛出异常{
    
        }
    }
    
  2. ExampleInstrumentedTest2:

    导入 android.support.test.rule.ActivityTestRule;
    
    导入 org.junit.Rule;
    导入 org.junit.Test;
    导入 org.junit.runner.RunWith;
    导入 org.junit.runners.JUnit4;
    
    @RunWith(JUnit4.class)
    公共类ExampleInstrumentedTest2 {
    
    
        @规则
        公共 ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class);
    
        @测试
        公共无效checkInputs()抛出异常{
    
        }
    }
    
  3. ExampleInstrumentedSuite:

    导入junit.framework.TestSuite;
    
    导入 org.junit.runner.RunWith;
    导入 org.junit.runners.AllTests;
    
    @RunWith(AllTests.class)
    公共类ExampleInstrumentedSuite {
    
        公共静态 TestSuite 套件(){
            TestSuite 套件 = new TestSuite();
            suite.addTest(new junit.framework.JUnit4TestAdapter(ExampleInstrumentedTest.class));
            suite.addTest(new junit.framework.JUnit4TestAdapter(ExampleInstrumentedTest2.class));
            返回套房;
        }
    }
    

请注意,您应该使用@RunWith(JUnit4.class)而不是默认的@RunWith(AndroidJUnit4.class)< /code> 在 testCase 类中

Here is a Complete example how to implement that. it combines of two testCase classes and one suite.

  1. ExampleInstrumentedTest:

    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 {
    
        }
    }
    
  2. ExampleInstrumentedTest2:

    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 {
    
        }
    }
    
  3. ExampleInstrumentedSuite:

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

Note that you should use @RunWith(JUnit4.class) instead of default @RunWith(AndroidJUnit4.class) in testCase Class

小矜持 2024-09-17 05:18:44
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;
    }
}
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;
    }
}
一个人的旅程 2024-09-17 05:18:44

扩展 @kissLife 的答案,您可以粘贴并运行以下内容,它可以动态创建多个测试:

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

public final class TestJunit4DynamicConstruction {
    public static TestSuite suite() {
        TestSuite suite = new TestSuite();
        suite.addTest(new CompareInts(1, 1));
        suite.addTest(new CompareInts(2, 2));
        suite.addTest(new CompareInts(2, 1)); // huh, for some reason, 2 != 1
        suite.addTest(new CompareInts(1, 1));
        return suite;
    }

    static public class CompareInts extends TestCase {
        private final int got;
        private final int expected;

        CompareInts(int got, int expected) {
            super(Integer.toString(got) + ":" + Integer.toString(expected));
            this.got = got;
            this.expected = expected;
        }
        @Override
        public void runTest() {
            assertEquals(got, expected);
        }
    }
}

您将运行这些测试:

TestJunit4DynamicConstruction$CompareInts.1:1
TestJunit4DynamicConstruction$CompareInts.2:2
TestJunit4DynamicConstruction$CompareInts.2:1
TestJunit4DynamicConstruction$CompareInts.1:1
TestJunit4DynamicConstruction$CompareInts

并收到此错误:

junit.framework.AssertionFailedError: 
Expected :2
Actual   :1


    ...
TestJunit4DynamicConstruction$CompareInts.runTest(TestJunit4DynamicConstruction.java:26)
   ...


Process finished with exit code 255

Expanding on @kissLife's answer, here's a something you can paste and run that creates multiple tests on the fly:

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

public final class TestJunit4DynamicConstruction {
    public static TestSuite suite() {
        TestSuite suite = new TestSuite();
        suite.addTest(new CompareInts(1, 1));
        suite.addTest(new CompareInts(2, 2));
        suite.addTest(new CompareInts(2, 1)); // huh, for some reason, 2 != 1
        suite.addTest(new CompareInts(1, 1));
        return suite;
    }

    static public class CompareInts extends TestCase {
        private final int got;
        private final int expected;

        CompareInts(int got, int expected) {
            super(Integer.toString(got) + ":" + Integer.toString(expected));
            this.got = got;
            this.expected = expected;
        }
        @Override
        public void runTest() {
            assertEquals(got, expected);
        }
    }
}

You'll run these tests:

TestJunit4DynamicConstruction$CompareInts.1:1
TestJunit4DynamicConstruction$CompareInts.2:2
TestJunit4DynamicConstruction$CompareInts.2:1
TestJunit4DynamicConstruction$CompareInts.1:1
TestJunit4DynamicConstruction$CompareInts

and get this error:

junit.framework.AssertionFailedError: 
Expected :2
Actual   :1


    ...
TestJunit4DynamicConstruction$CompareInts.runTest(TestJunit4DynamicConstruction.java:26)
   ...


Process finished with exit code 255
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文