一遍又一遍运行相同的联合测试的简单方法?

正如标题所说,我正在寻找一种简单的方法,使用 Eclipse 自动地在一行中多次运行 JUnit 4.x 测试。

例如,在一行中运行同一个测试10次并报告结果。

我们已经有了一个复杂的方法来解决这个问题,但是我正在寻找一个简单的方法来解决这个问题,这样我就可以保证我一直试图修复的片状测试能够保持不变。

一个理想的解决方案是 Eclipse 插件/设置/特性,但我不知道。

133230 次浏览

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

@Repeat(value = 10)

最新(Spring 框架4.3.11. 释放 API)文档:

做到这一点的最简单方法(至少需要大量的新代码)是将测试作为参数化测试运行(使用 @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接口,以便它在 for 循环中执行该语句10次。这种方法目前的缺点是 @Before@After只运行一次。这可能会在 JUnit 的下一个版本中改变(@Before将在 @Rule之后运行) ,但是无论如何,您都将对对象的相同实例执行操作(对于 Parameterized运行程序来说是不正确的)。这假设您使用的运行类的运行程序能够正确识别 @Rule注释。只有在将委托给 JUnit 运行程序时才会出现这种情况。

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

注意,还有其他可能解决这个问题的方法(比如理论跑步者) ,但是他们都需要一个跑步者。不幸的是,JUnit 目前不支持运行程序层。这是一个运动员,链其他运动员。

有什么问题吗:

@Test
void itWorks() {
// stuff
}


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

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

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

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中的 IntermitentTestRunner) ,testCounter将等于99。

这对我来说容易多了。

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

受以下资源启发:

例子

创建并使用如下 @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.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;
}

重复 Rule.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(其中包括 补丁)。

我构建了一个允许进行这类测试的模块。但它的重点不仅在于重复。但是在保证某段代码是线程安全的情况下。

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

专家依赖:

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

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

使用 JUnit 5,我能够使用 @ 重复测试注释解决这个问题:

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

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

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


}
}


}


}

使用 IntelliJ,您可以从测试配置中完成这项工作。打开此窗口后,可以选择运行测试的任意次数。

enter image description here

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

例如,10次运行624个测试: enter image description here

这基本上就是上文在 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() { }
}