首页 文章

一遍又一遍地运行相同的junit测试的简单方法?

提问于
浏览
83

就像 Headers 所说,我正在寻找一些使用Eclipse自动连续多次运行JUnit 4.x测试的简单方法 .

一个例子是连续10次运行相同的测试并报告结果 .

我们已经有了一个复杂的方法来做这个,但我正在寻找一种简单的方法来做到这一点,以便我可以确定我一直试图修复的片状测试保持固定 .

一个理想的解决方案是我不知道的Eclipse插件/设置/功能 .

11 回答

  • 7

    最简单的(至少需要新代码量)方法是将测试作为参数化测试运行(使用_1755680注释并添加一个方法以提供10个空参数) . 这样,框架将运行测试10次 .

    这个测试需要是该类中唯一的测试,或者更好的是所有测试方法都需要在类中运行10次 .

    这是一个例子:

    @RunWith(Parameterized.class)
    public class RunTenTimes {
    
        @Parameterized.Parameters
        public static Object[][] data() {
            return new Object[10][0];
        }
    
        public RunTenTimes() {
        }
    
        @Test
        public void runsTenTimes() {
            System.out.println("run");
        }
    }
    

    有了上述内容,甚至可以使用无参数构造函数来完成它,但我不确定框架作者是否打算这样做,或者将来是否会破坏 .

    如果您正在实施自己的跑步者,那么您可以让跑步者进行10次测试 . 如果您正在使用第三方运行程序,那么使用4.7,您可以使用新的 @Rule 注释并实现 MethodRule 接口,以便它接受语句并在for循环中执行10次 . 这种方法目前的缺点是 @Before@After 只运行一次 . 这可能会在JUnit的下一个版本中发生变化( @Before 将在 @Rule 之后运行),但无论你是在同一个对象实例上行动(对于 Parameterized 跑步者来说都是如此) . 这假设您正在运行该类的任何跑步者正确识别 @Rule 注释 . 只有当它委托给JUnit运行者时才会这样 .

    如果您使用的是不能识别 @Rule 注释的自定义运行器,那么您真的不得不编写自己的运行程序,该运行程序适当地委派给Runner并运行10次 .

    请注意,还有其他方法可以解决这个问题(例如Theories runner),但它们都需要跑步者 . 不幸的是,JUnit目前不支持跑步者层 . 这是一个连锁其他选手的跑步者 .

  • 9

    我发现Spring的重复注释对于这种事情很有用:

    @Repeat(value = 10)
    

    最新(Spring Framework 4.3.11.RELEASE API)doc:

  • 41

    使用IntelliJ,您可以从测试配置中执行此操作 . 打开此窗口后,您可以选择任意次数运行测试 .

    enter image description here

    当您运行测试时,intellij将按您指定的次数执行您选择的所有测试 .

    示例运行624次测试10次:
    enter image description here

  • 28

    灵感来自this solution

    像这样使用 @Repeat 注释:

    public class MyTestClass {
    
        @Rule
        public RepeatRule repeatRule = new RepeatRule();
    
        @Test
        @Repeat(10)
        public void testMyCode() {
            //your test code goes here
        }
    }
    

    你只需要这两个类:

    Repeat.java:

    import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
    import static java.lang.annotation.ElementType.METHOD;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention( RetentionPolicy.RUNTIME )
    @Target({ METHOD, ANNOTATION_TYPE })
    public @interface Repeat {
        int value() default 1;
    }
    

    RepeatRule.java:

    import org.junit.rules.TestRule;
    import org.junit.runner.Description;
    import org.junit.runners.model.Statement;
    
    public class RepeatRule implements TestRule {
    
        private static class RepeatStatement extends Statement {
            private final Statement statement;
            private final int repeat;    
    
            public RepeatStatement(Statement statement, int repeat) {
                this.statement = statement;
                this.repeat = repeat;
            }
    
            @Override
            public void evaluate() throws Throwable {
                for (int i = 0; i < repeat; i++) {
                    statement.evaluate();
                }
            }
    
        }
    
        @Override
        public Statement apply(Statement statement, Description description) {
            Statement result = statement;
            Repeat repeat = description.getAnnotation(Repeat.class);
            if (repeat != null) {
                int times = repeat.value();
                result = new RepeatStatement(statement, times);
            }
            return result;
        }
    }
    

    2016-10-25 Edit: 为了在使用 @RunWith(PowerMockRunner.class) 时使用此解决方案,请更新为Powermock 1.6.5(包括this patch) .

  • 7

    使用JUnit 5,我能够使用@RepeatedTest注释来解决这个问题:

    @RepeatedTest(10)
    public void testMyCode() {
        //your test code goes here
    }
    

    请注意, @Test 注释不应与 @RepeatedTest 一起使用 .

  • 106

    有什么不妥:

    @Test
    void itWorks() {
        // stuff
    }
    
    @Test
    void itWorksRepeatably() {
        for (int i = 0; i < 10; i++) {
            itWorks();
        }
    }
    

    与测试每个值数组的情况不同,您并不特别关心哪个运行失败 .

    无需在配置或注释中执行代码中的操作 .

  • 16

    这对我来说更容易 .

    public class RepeatTests extends TestCase {
    
        public static Test suite() {
            TestSuite suite = new TestSuite(RepeatTests.class.getName());
    
            for (int i = 0; i < 10; i++) {              
            suite.addTestSuite(YourTest.class);             
            }
    
            return suite;
        }
    }
    
  • 0

    tempus-fugit库中有一个Intermittent注释,它与JUnit 4.7的 @Rule 一起重复测试几次或使用 @RunWith .

    例如,

    @RunWith(IntermittentTestRunner.class)
    public class IntermittentTestRunnerTest {
    
       private static int testCounter = 0;
    
       @Test
       @Intermittent(repition = 99)
       public void annotatedTest() {
          testCounter++;
       }
    }
    

    运行测试后(使用 @RunWith 中的IntermittentTestRunner), testCounter 将等于99 .

  • 0

    我构建了一个允许进行此类测试的模块 . 但它的重点不仅在于重复 . 但是保证一些代码是Thread安全的 .

    https://github.com/anderson-marques/concurrent-testing

    Maven依赖:

    <dependency>
        <groupId>org.lite</groupId>
        <artifactId>concurrent-testing</artifactId>
        <version>1.0.0</version>
    </dependency>
    

    使用示例:

    package org.lite.concurrent.testing;
    
    import org.junit.Assert;
    import org.junit.Rule;
    import org.junit.Test;
    import ConcurrentTest;
    import ConcurrentTestsRule;
    
    /**
     * Concurrent tests examples
     */
    public class ExampleTest {
    
        /**
         * Create a new TestRule that will be applied to all tests
         */
        @Rule
        public ConcurrentTestsRule ct = ConcurrentTestsRule.silentTests();
    
        /**
         * Tests using 10 threads and make 20 requests. This means until 10 simultaneous requests.
         */
        @Test
        @ConcurrentTest(requests = 20, threads = 10)
        public void testConcurrentExecutionSuccess(){
            Assert.assertTrue(true);
        }
    
        /**
         * Tests using 10 threads and make 20 requests. This means until 10 simultaneous requests.
         */
        @Test
        @ConcurrentTest(requests = 200, threads = 10, timeoutMillis = 100)
        public void testConcurrentExecutionSuccessWaitOnly100Millissecond(){
        }
    
        @Test(expected = RuntimeException.class)
        @ConcurrentTest(requests = 3)
        public void testConcurrentExecutionFail(){
            throw new RuntimeException("Fail");
        }
    }
    

    这是一个开源项目 . 随意改进 .

  • 55

    您可以从main方法运行JUnit测试并重复它所需的次数:

    package tests;
    
    import static org.junit.Assert.*;
    
    import org.junit.Test;
    import org.junit.runner.Result;
    
    public class RepeatedTest {
    
        @Test
        public void test() {
            fail("Not yet implemented");
        }
    
        public static void main(String args[]) {
    
            boolean runForever = true;
    
            while (runForever) {
                Result result = org.junit.runner.JUnitCore.runClasses(RepeatedTest.class);
    
                if (result.getFailureCount() > 0) {
                    runForever = false;
                   //Do something with the result object
    
                }
            }
    
        }
    
    }
    
  • 0

    这基本上就是Yishai在Kotlin上重写的答案:

    @RunWith(Parameterized::class)
    class MyTest {
    
        companion object {
    
            private const val numberOfTests = 200
    
            @JvmStatic
            @Parameterized.Parameters
            fun data(): Array<Array<Any?>> = Array(numberOfTests) { arrayOfNulls<Any?>(0) }
        }
    
        @Test
        fun testSomething() { }
    }
    

相关问题