在 Junit 中使用类别时如何使用自定义运行程序?

How can I use a custom runner when using categories in Junit?

我有一堆 JUnit 测试扩展了我的基础测试 class,称为 BaseTest,后者又扩展了 Assert。我的一些测试有一个 @Category(SlowTests.class) 注释。

我的 BaseTest class 被注释为以下注释 @RunWith(MyJUnitRunner.class)

我设置了一个 Gradle 任务,预计 运行 仅 SlowTests。这是我的 Gradle 任务:

task integrationTests(type: Test) {
    minHeapSize = "768m"
    maxHeapSize = "1024m"
    testLogging {
        events "passed", "skipped", "failed"
        outputs.upToDateWhen {false}
    }
    reports.junitXml.destination = "$buildDir/test-result"
    useJUnit {
        includeCategories 'testutils.SlowTests'
    }
}

当我 运行 任务时,我的测试不是 运行。我已确定此问题与 BaseTest 上的自定义 运行ner MyJUnitRunner 有关。如何设置我的 Gradle 或测试结构,以便在使用 Suite.

时可以使用自定义 运行ner

事实证明,这个问题的解决方案比我想象的更小、更棘手。 Gradle 正在使用我的自定义测试 运行ner 并正确调用 filter 方法。但是,我的 运行ner 通过它自己的 classloader 重新加载所有测试 classes 以增强 Javaassist。

这导致了 SlowTest 注释是通过 Gradle class 加载器加载的问题,但是当传递到我的自定义 运行ner 时,运行ner 检查 class 是否用该注释进行了注释。由于通过两个不同的 class 加载程序加载的 SlowTest 注释的相等性不同,因此此检查从未正确解决。

--

既然我已经做了研究,我就把它留在这里。经过几天对 Gradle 和(神秘的)JUnit 资源的挖掘,这就是我得到的。

Gradle 除了测试分类外,不处理任何高级 JUnit 功能。当您使用 include-categories 或 exclude-categories 条件创建 Gradle 任务时,它会构建一个 CategoryFilter。如果你不知道,一个 Filter 是 JUnit 给 test-运行ner 的东西,用来决定是否应该过滤掉一个测试或测试方法。测试 运行ner 必须实现 Filterable 接口。

JUnit 带有多个 运行ners,Categories 只是其中的一个。它扩展了一个名为 Suite 的测试 运行ners 家族。这些基于套件的 运行ners 旨在 运行 "suite" 测试。可以通过注释内省、在套件中显式定义测试或构建测试套件的任何其他方法来构建测试套件。

对于 Categories 运行ner,JUnit 有它自己的 CategoryFilter but Gradle doesn't use that, it uses it's own CategoryFilter。两者都提供或多或少相同的功能,并且都是 JUnit 过滤器,因此可以被任何实现 Filterable.

的套件使用

Gradle 中负责 运行JUnit 测试的实际 class 称为 JUnitTestClassExecuter. Once it has parsed the command line options it requests JUnit to check the runner should be used for a test. This method is invoked for every test as seen here

剩下的就看 JUnit 了。 Gradle 刚刚创建了一个自定义 RunNotifier 来生成代表测试结果的标准 XML 文件。

我希望有人觉得这很有用,并为自己节省了无数小时的调试时间。

TLDR:您可以使用 Gradle 中的任何 运行ner。 Gradle 没有关于 运行ners 的细节。是 JUnit 决定了 运行 人。如果你想知道什么 运行ner 将用于你的测试,你可以通过调用来调试它 Request.aClass(testClass).getRunner()。将其破解到您的代码库中并将其打印到控制台。 (我没有很成功地将调试器附加到 Gradle。)