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

发布于 2024-08-06 01:28:32 字数 208 浏览 4 评论 0原文

正如标题所示,我正在寻找一些简单的方法来使用 Eclipse 自动连续多次运行 JUnit 4.x 测试。

例如,连续运行相同的测试 10 次并报告结果。

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

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

Like the title says, I'm looking for some simple way to run JUnit 4.x tests several times in a row automatically using Eclipse.

An example would be running the same test 10 times in a row and reporting back the result.

We already have a complex way of doing this but I'm looking for a simple way of doing it so that I can be sorta sure that the flaky test I've been trying to fix stays fixed.

An ideal solution would be an Eclipse plugin/setting/feature that I am unaware of.

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

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

发布评论

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

评论(11

心奴独伤 2024-08-13 01:28:32

最简单(需要最少数量的新代码)的方法是将测试作为参数化测试运行(使用 @RunWith(Parameterized.class) 进行注释并添加一个方法来提供 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 接口,以便它接受语句并执行它 10 for 循环中的次数。此方法当前的缺点是 @Before@After 仅运行一次。这可能会在 JUnit 的下一个版本中发生变化(@Before 将在 @Rule 之后运行),但无论如何您都会对对象的同一个实例进行操作(对于参数化运行器来说并非如此)。这假设您运行类的任何运行程序都可以正确识别 @Rule 注释。仅当委托给 JUnit 运行程序时才会出现这种情况。

如果您使用无法识别 @Rule 注释的自定义运行程序运行,那么您实际上必须编写自己的运行程序来适当地委托给该运行程序并运行它 10 次。

请注意,还有其他方法可以潜在地解决此问题(例如理论运行程序),但它们都需要运行程序。不幸的是,JUnit 目前不支持运行器层。那是一个链着其他跑步者的跑步者。

The easiest (as in least amount of new code required) way to do this is to run the test as a parametrized test (annotate with an @RunWith(Parameterized.class) and add a method to provide 10 empty parameters). That way the framework will run the test 10 times.

This test would need to be the only test in the class, or better put all test methods should need to be run 10 times in the class.

Here is an example:

@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");
    }
}

With the above, it is possible to even do it with a parameter-less constructor, but I'm not sure if the framework authors intended that, or if that will break in the future.

If you are implementing your own runner, then you could have the runner run the test 10 times. If you are using a third party runner, then with 4.7, you can use the new @Rule annotation and implement the MethodRule interface so that it takes the statement and executes it 10 times in a for loop. The current disadvantage of this approach is that @Before and @After get run only once. This will likely change in the next version of JUnit (the @Before will run after the @Rule), but regardless you will be acting on the same instance of the object (something that isn't true of the Parameterized runner). This assumes that whatever runner you are running the class with correctly recognizes the @Rule annotations. That is only the case if it is delegating to the JUnit runners.

If you are running with a custom runner that does not recognize the @Rule annotation, then you are really stuck with having to write your own runner that delegates appropriately to that Runner and runs it 10 times.

Note that there are other ways to potentially solve this (such as the Theories runner) but they all require a runner. Unfortunately JUnit does not currently support layers of runners. That is a runner that chains other runners.

绻影浮沉 2024-08-13 01:28:32

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

输入图像描述这里

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

运行 624 个测试 10 次的示例:
输入图像描述这里

With IntelliJ, you can do this from the test configuration. Once you open this window, you can choose to run the test any number of times you want,.

enter image description here

when you run the test, intellij will execute all tests you have selected for the number of times you specified.

Example running 624 tests 10 times:
enter image description here

柏林苍穹下 2024-08-13 01:28:32

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

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

请注意,@Test 注解不应与 @RepeatedTest 一起使用。

With JUnit 5 I was able to solve this using the @RepeatedTest annotation:

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

Note that @Test annotation shouldn't be used along with @RepeatedTest.

黄昏下泛黄的笔记 2024-08-13 01:28:32

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

@Repeat(value = 10)

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

I've found that Spring's repeat annotation is useful for that kind of thing:

@Repeat(value = 10)

Latest (Spring Framework 4.3.11.RELEASE API) doc:

狼性发作 2024-08-13 01:28:32

受到以下资源的启发:

示例

创建并使用 @Repeat 注解,如下所示:

public class MyTestClass {

    @Rule
    public RepeatRule repeatRule = new RepeatRule();

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

重复.java

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

PowerMock

将此解决方案与 @RunWith(PowerMockRunner.class) 一起使用,需要更新到 Powermock 1.6.5 (其中包括 补丁)。

Inspired by the following resources:

Example

Create and use a @Repeat annotation as follows:

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.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(METHOD)
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;
    }
}

PowerMock

Using this solution with @RunWith(PowerMockRunner.class), requires updating to Powermock 1.6.5 (which includes a patch).

找个人就嫁了吧 2024-08-13 01:28:32

任何问题:

@Test
void itWorks() {
    // stuff
}

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

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

无需在配置或注释中执行您可以在代码中执行的操作。

Anything wrong with:

@Test
void itWorks() {
    // stuff
}

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

Unlike the case where you are testing each of an array of values, you don't particularly care which run failed.

No need to do in configuration or annotation what you can do in code.

安稳善良 2024-08-13 01:28:32

这对我来说更容易。

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

This works much easier for me.

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;
    }
}
哆兒滾 2024-08-13 01:28:32

tempus-fugit 库中有一个间歇性注释,可与 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。

There's an Intermittent annotation in the tempus-fugit library which works with JUnit 4.7's @Rule to repeat a test several times or with @RunWith.

For example,

@RunWith(IntermittentTestRunner.class)
public class IntermittentTestRunnerTest {

   private static int testCounter = 0;

   @Test
   @Intermittent(repition = 99)
   public void annotatedTest() {
      testCounter++;
   }
}

After the test is run (with the IntermittentTestRunner in the @RunWith), testCounter would be equal to 99.

清旖 2024-08-13 01:28:32

这本质上是 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() { }
}

This is essentially the answer that Yishai provided above, re-written in 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() { }
}
辞取 2024-08-13 01:28:32

我构建了一个允许进行此类测试的模块。但它不仅仅专注于重复。但要保证某段代码是线程安全的。

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

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

I build a module that allows do this kind of tests. But it is focused not only in repeat. But in guarantee that some piece of code is Thread safe.

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

Maven dependency:

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

Example of use:

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

This is a open source project. Feel free to improve.

舟遥客 2024-08-13 01:28:32

您可以从 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

            }
        }

    }

}

You could run your JUnit test from a main method and repeat it so many times you need:

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

            }
        }

    }

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