如何使 JUnit 测试按随机顺序运行?

发布于 2024-08-05 07:28:26 字数 236 浏览 2 评论 0原文

我有经典的测试结构,我有一个由不同套件组成的测试套件,例如 DatabaseTests、UnitTests 等。有时这些套件包含其他套件,例如 SlowDatabaseTests、FastDatabaseTests 等。

我想要的是随机化测试的运行顺序,这样我将确保他们并不相互依赖。随机化应该在每个级别上进行,就像套件应该打乱测试类顺序一样,测试类应该打乱测试方法顺序。

如果可以在 Eclipse 中做到这一点那就最好了。

I have the classical structure for tests, I have a test suite of different suites like DatabaseTests, UnitTests etc. Sometimes those suites contains other suites like SlowDatabaseTests, FastDatabaseTests etc.

What I want is to randomize the running order of tests so I will make sure they are not dependent to each other. Randomization should be at every level, like suite should shuffle test class order, and test class should shuffle test method order.

If it is possible to do this in Eclipse that will be the best.

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

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

发布评论

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

评论(7

笑红尘 2024-08-12 07:28:26

你确实有一个 Sortable 但我可以'不知道你会如何使用它。

您可以扩展 BlockJUnit4ClassRunner 并拥有 computeTestMethods() 返回 super.computeTestMethods( 的随机副本)。然后使用 @RunWith 将其设置为运行程序使用。

例如

package com.stackoverflow.mlk;

import java.util.Collections;

import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;

public class RandomBlockJUnit4ClassRunner extends BlockJUnit4ClassRunner {

    public RandomBlockJUnit4ClassRunner(Class<?> klass)
            throws InitializationError {
        super(klass);
    }

    protected java.util.List<org.junit.runners.model.FrameworkMethod> computeTestMethods() {
        java.util.List<org.junit.runners.model.FrameworkMethod> methods = super.computeTestMethods();
        Collections.shuffle(methods);
        return methods;
    }

}

然后

@RunWith(com.stackoverflow.mlk.RandomBlockJUnit4ClassRunner.class)
public class RandomOrder {
    @Test
    public void one() {
    }

    @Test
    public void two() {
    }

    @Test
    public void three() {
    }
}

You do have a Sortable but I can't see how you would use it.

You could extend BlockJUnit4ClassRunner and have computeTestMethods() return a randomized copy of super.computeTestMethods(). Then use the @RunWith to set that as the runner to use.

e.g.

package com.stackoverflow.mlk;

import java.util.Collections;

import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;

public class RandomBlockJUnit4ClassRunner extends BlockJUnit4ClassRunner {

    public RandomBlockJUnit4ClassRunner(Class<?> klass)
            throws InitializationError {
        super(klass);
    }

    protected java.util.List<org.junit.runners.model.FrameworkMethod> computeTestMethods() {
        java.util.List<org.junit.runners.model.FrameworkMethod> methods = super.computeTestMethods();
        Collections.shuffle(methods);
        return methods;
    }

}

Then

@RunWith(com.stackoverflow.mlk.RandomBlockJUnit4ClassRunner.class)
public class RandomOrder {
    @Test
    public void one() {
    }

    @Test
    public void two() {
    }

    @Test
    public void three() {
    }
}
梦忆晨望 2024-08-12 07:28:26

https://github.com/KentBeck/junit/pull/386 引入了一些订单,但是不是随机。也许你并不真正想要这个;测试应该确定性地运行。如果您需要验证测试的不同排列是否仍然通过,请测试所有排列;或者,如果这速度慢得不切实际,请引入由环境变量等确定的“随机”种子进行洗牌,以便您可以重现任何故障。 http://hg.netbeans.org /main/file/66d9fb12e98f/nbjunit/src/org/netbeans/junit/MethodOrder.java 给出了针对 JUnit 3 执行此操作的示例。

https://github.com/KentBeck/junit/pull/386 introduces some orders but not RANDOM. Probably you do not really want this; tests should run deterministically. If you need to verify that different permutations of tests still pass, either test all permutations; or, if this would be impractically slow, introduce a “random” seed for shuffling that is determined by an environment variable or the like, so that you can reproduce any failures. http://hg.netbeans.org/main/file/66d9fb12e98f/nbjunit/src/org/netbeans/junit/MethodOrder.java gives an example of doing this for JUnit 3.

不必你懂 2024-08-12 07:28:26

一般来说,您需要做的是编写自己的测试运行程序,并在测试运行程序类中聚合方法并随机运行每个测试(确保不会运行测试两次)。

在此处阅读有关测试框架以及如何编写自己的测试运行程序的更多信息:
http://www.ddj.com/architect/184415674

In general what you need to do is to write your own test runner and in the test runner class aggregate the methods and randomly run each test (make sure you don't run a test twice).

Read more about the test framework and how to write your own test runner here:
http://www.ddj.com/architect/184415674

诗化ㄋ丶相逢 2024-08-12 07:28:26

在 JUnit 4.13 中,要以随机顺序运行测试类中的测试,请编写一个小帮助器类:

import org.junit.runner.manipulation.Ordering;

import java.util.Random;

public class RandomOrder implements Ordering.Factory {
    @Override
    public Ordering create(Ordering.Context context) {
        long seed = new Random().nextLong();
        System.out.println("RandomOrder: seed = " + seed);
        return Ordering.shuffledBy(new Random(seed));
    }
}

然后,用以下内容注释您的测试类:

@OrderWith(RandomOrder.class)

这样,该类的测试方法就会以随机顺序运行。另外,如果它们意外失败,您知道随机种子会完全重复此顺序。

我不知道如何为整个项目或测试套件配置它。

In JUnit 4.13, to run the tests within a test class in random order, write a small helper class:

import org.junit.runner.manipulation.Ordering;

import java.util.Random;

public class RandomOrder implements Ordering.Factory {
    @Override
    public Ordering create(Ordering.Context context) {
        long seed = new Random().nextLong();
        System.out.println("RandomOrder: seed = " + seed);
        return Ordering.shuffledBy(new Random(seed));
    }
}

Then, annotate your test class with:

@OrderWith(RandomOrder.class)

This way, the test methods of this one class are run in random order. Plus, if they unexpectedly fail, you know the random seed to repeat exactly this order.

I don't know though how to configure this for a whole project or a test suite.

夜无邪 2024-08-12 07:28:26

这是使用 GradleJUnit 5.8.0 的解决方案

第 1 步:确保您具有最新的 JUnit 版本依赖项。
步骤 2:在 build.gradle 测试部分定义所需的属性

test {  
    useJUnitPlatform()
    systemProperties([
         //Random in method level
        'junit.jupiter.testmethod.order.default': 'org.junit.jupiter.api.MethodOrderer$Random', 
         // Random in class level
        'junit.jupiter.testclass.order.default' : 'org.junit.jupiter.api.ClassOrderer$Random',
        // Log configuration to see the seed
        'java.util.logging.config.file' : file('src/test/resources/logging.properties')
    ])
    //To print the JUnit logs in console
    testLogging {
        events "passed", "skipped", "failed", "standardOut", "standardError"
    }
}

步骤 3:在 src/test/resources 下定义 logging.properties

.level=CONFIG
java.util.logging.ConsoleHandler.level=CONFIG
org.junit.jupiter.api.ClassOrderer$Random.handlers=java.util.logging.ConsoleHandler
org.junit.jupiter.api.MethodOrderer$Random.handlers=java.util.logging.ConsoleHandler

步骤 4:运行测试。 gradlew clean test

您可以在控制台中看到用于随机测试的种子。

CONFIG: ClassOrderer.Random default seed: 65423695211256721
CONFIG: MethodOrderer.Random default seed: 6542369521653287

如果是片状测试,您可以通过配置 JUnit 测试失败的相同种子来重现它

systemProperties([
'junit.jupiter.execution.class.order.random.seed' : '65423695211256721'
'junit.jupiter.execution.order.random.seed'       : '6542369521653287'
])

参考:how-to-randomize-tests-in-junit随机

Here is a solution with Gradle and JUnit 5.8.0

Step 1 : Ensure that you have latest JUnit version dependency.
Step 2 : Define the required properties under build.gradle test section

test {  
    useJUnitPlatform()
    systemProperties([
         //Random in method level
        'junit.jupiter.testmethod.order.default': 'org.junit.jupiter.api.MethodOrderer$Random', 
         // Random in class level
        'junit.jupiter.testclass.order.default' : 'org.junit.jupiter.api.ClassOrderer$Random',
        // Log configuration to see the seed
        'java.util.logging.config.file' : file('src/test/resources/logging.properties')
    ])
    //To print the JUnit logs in console
    testLogging {
        events "passed", "skipped", "failed", "standardOut", "standardError"
    }
}

Step 3: Define logging.properties under src/test/resources

.level=CONFIG
java.util.logging.ConsoleHandler.level=CONFIG
org.junit.jupiter.api.ClassOrderer$Random.handlers=java.util.logging.ConsoleHandler
org.junit.jupiter.api.MethodOrderer$Random.handlers=java.util.logging.ConsoleHandler

Step 4 : Run test. gradlew clean test

You can see the seed used for the random test in the console

CONFIG: ClassOrderer.Random default seed: 65423695211256721
CONFIG: MethodOrderer.Random default seed: 6542369521653287

In case of flaky test, you can reproduce it by configuring the same seed where the JUnit tests were failing

systemProperties([
'junit.jupiter.execution.class.order.random.seed' : '65423695211256721'
'junit.jupiter.execution.order.random.seed'       : '6542369521653287'
])

References : how-to-randomize-tests-in-junit , Random

两仪 2024-08-12 07:28:26

我会确保他们不依赖于
彼此

应该确保情况确实如此,而不依赖于随机执行顺序。是什么让您担心依赖关系可能存在?

I will make sure they are not dependent to
each other

You should make sure that this is the case without relying on random execution order. What makes you fear that dependencies may exist?

◇流星雨 2024-08-12 07:28:26

这个问题在 JUnit GitHub 上公开已有 2 年了,并指出了 2 个独立的问题问题:
- 根据执行顺序进行测试;
- 不可重复的测试。

考虑从根本上解决问题,而不是事后尝试使用框架来完成工作。使用setUp和tearDown方法保证隔离性,并在最小级别进行测试。

This issue is open on JUnit GitHub since 2 years, and point out 2 independent issues:
- Tests depending on the execution order;
- Non repeatable tests.

Consider adressing the issue at the root, rather than trying to use the framework to do the job afterwards. Use setUp and tearDown method to guarantee isolation, and test at the smallest level.

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