JUnit 测试类顺序

2022-09-02 12:25:29

我有一个带有maven的java应用程序。Junit 用于测试,带有故障安全和 surefire 插件。我有2000多个集成测试。为了加快测试运行速度,我使用故障安全 jvmfork 并行运行我的测试。我有一些繁重的测试类,它们通常在我的测试执行结束时运行,这会减慢我的CI验证过程。filesafe runorder:balanced对我来说是一个不错的选择,但我不能使用它,因为jvmfork。重命名测试类或移动到另一个包并运行它,alpahabetical 不是一个选项。任何建议,如何在验证过程开始时运行慢速测试类?


答案 1

JUnit 5(从 5.8.0 版本开始)中,也可以对测试类进行排序。

src/test/resources/junit-platform.properties

# ClassOrderer$OrderAnnotation sorts classes based on their @Order annotation
junit.jupiter.testclass.order.default=org.junit.jupiter.api.ClassOrderer$OrderAnnotation

其他 Junit 内置类排序器实现:

org.junit.jupiter.api.ClassOrderer$ClassName
org.junit.jupiter.api.ClassOrderer$DisplayName
org.junit.jupiter.api.ClassOrderer$Random

有关设置配置参数的其他方法(除了 junit-platform.properties 文件之外),请参阅 JUnit 5 用户指南

您也可以提供自己的订购人。它必须实现接口:ClassOrderer

package foo;
public class MyOrderer implements ClassOrderer {
    @Override
    public void orderClasses(ClassOrdererContext context) {
        Collections.shuffle(context.getClassDescriptors());
    }
}
junit.jupiter.testclass.order.default=foo.MyOrderer

请注意,测试类不能按 排序。@NestedClassOrderer

请参阅 JUnit 5 文档和 ClassOrderer API 文档以了解有关此内容的更多信息。


答案 2

我给出了我找到的答案组合:尝试一下:

第二个答案是基于这个github项目的这些,该项目在BSD-2许可证下可用。

我定义了几个测试类:

public class LongRunningTest {

    @Test
    public void test() {

        System.out.println(Thread.currentThread().getName() + ":\tlong test - started");

        long time = System.currentTimeMillis();
        do {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        } while(System.currentTimeMillis() - time < 1000);

        System.out.println(Thread.currentThread().getName() + ":\tlong test - done");
    }
}
@Concurrent
public class FastRunningTest1 {

    @Test
    public void test1() {
        try {
            Thread.sleep(250);
        } catch (InterruptedException e) {
        }

        System.out.println(Thread.currentThread().getName() + ":\tfrt1-test1 - done");
    }

    // +7 more repetions of the same method
}

然后我定义了测试套件:
(FastRunningTest2是第一个类的副本,具有调整的输出)

@SuiteClasses({LongRunningTest.class, LongRunningTest.class})
@RunWith(Suite.class)
public class SuiteOne {}

@SuiteClasses({FastRunningTest1.class, FastRunningTest2.class})
@RunWith(Suite.class)
public class SuiteTwo {}

@SuiteClasses({SuiteOne.class, SuiteTwo.class})
@RunWith(ConcurrentSuite.class)
public class TopLevelSuite {}

当我执行 时,我得到以下输出:TopLevelSuite

TopLevelSuite-1-thread-1: long test - started FastRunningTest1-1-thread-4: frt1-test4 - done FastRunningTest1-1-thread-2: frt1-test2 - done FastRunningTest1-1-thread-1: frt1-test1 - done FastRunningTest1-1-thread-3: frt1-test3 - done FastRunningTest1-1-thread-5: frt1-test5 - done FastRunningTest1-1-thread-3: frt1-test6 - done FastRunningTest1-1-thread-1: frt1-test8 - done FastRunningTest1-1-thread-5: frt1-test7 - done FastRunningTest2-2-thread-1: frt2-test1 - done FastRunningTest2-2-thread-2: frt2-test2 - done FastRunningTest2-2-thread-5: frt2-test5 - done FastRunningTest2-2-thread-3: frt2-test3 - done FastRunningTest2-2-thread-4: frt2-test4 - done TopLevelSuite-1-thread-1: long test - done TopLevelSuite-1-thread-1: long test - started FastRunningTest2-2-thread-5: frt2-test8 - done FastRunningTest2-2-thread-2: frt2-test6 - done FastRunningTest2-2-thread-1: frt2-test7 - done TopLevelSuite-1-thread-1: long test - done

这基本上表明 在 parralel 中执行到 .注释定义的用于并行执行的线程的默认值为 ,这可以在 并行执行的输出中看到。LongRunningTestFastRunningTestsConcurrent5FastRunningTests

缺点是 这些论文在 和 之间不共享。ThreadsFastRunningTest1FastRunningTest2


这种行为表明,“在某种程度上”可以做你想做的事情(所以这是否适用于你当前的设置是另一个问题)。

我也不确定这是否真的值得付出努力,

  • 因为您需要手动准备它们(或编写一些自动生成它们的东西)TestSuites
  • 并且您需要为所有这些类定义并发注释(每个类可能具有不同数量的注释)threads

由于这基本上表明可以定义类的执行顺序并触发它们的并行执行,因此也应该可能使整个过程仅使用一个(但我不确定这意味着什么)。ThreadPool

由于整个概念基于ThreadPoolExecutor,因此使用a可以为长时间运行的任务提供更高的优先级,您将更接近首先执行长时间运行的测试的理想结果。PriorityBlockingQueue


我进行了更多的实验,并实现了我自己的自定义套件运行器和 junit 运行器。背后的想法是让你的JUnitRunner将测试提交到一个队列中,该队列由单个.因为我没有在方法中实现阻塞操作,所以我最终得到了一个解决方案,其中所有类的测试在执行开始之前都传递到队列。(如果涉及更多的测试类和方法,则可能会有所不同)。ThreadPoolExecutorRunnerScheduler#finish

至少它证明了一点,如果你真的想,你可以在这个层面上搞砸junit。

我的poc的代码有点混乱,放在这里很长,但如果有人感兴趣,我可以把它推到github项目中。


推荐