我正在尝试将我的测试区分为单元测试和集成测试。 我的想法是使用新的JUnit5注释@Tag("unit")
它非常适合我的JUnit测试,但我无法让它与Spek一起使用。
我目前拥有的是我的班级:
data class MyObject(val value: Int)
我的测试:
@Tag("unit")
object MyObjectTest {
@Test
fun checkEquality() {
val o1 = MyObject(1)
assertEquals(o1, o1)
}
}
随着我的build.gradle有:
task utest(type: Test) {
outputs.upToDateWhen { false }
useJUnitPlatform {
includeEngines 'junit-jupiter', 'junit-vintage', 'spek'
includeTags 'unit'
excludeTags 'performance', 'integration', 'functional'
}
testLogging {
events "passed", "skipped", "failed"
}
}
当我执行 utest 时,这有效。 但是,当对 Spek 执行相同操作时:
@Tag("unit")
object MyObjectSpek : Spek({
given("an Object") {
val o1 = MyObject(1)
it("should be equal to itself") {
assertEquals(o1, o1)
}
}
})
发生的情况是,如果我运行 gradle 任务 utest,它只执行MyObjectTest
中的方法,而不执行MyObjectSpek
关于如何将 Spek 与 JUnit5 标签集成或其他想法以分离单元测试和集成测试的任何想法?
今天我遇到了同样的问题。我不得不将测试分为 3 个部分:单元、服务(测试 REST API(和集成(WebDriver(。
声明者:本指南适用于任何测试框架,不仅适用于Spek
。 运行此命令需要Gradle 4.6
或更高版本。
将测试源集分离到源集中
在我的示例中,它们是:
src/test
— 用于单元测试(您已经拥有它(src/serviceTest
— 用于服务测试src/integrationTest
— 用于集成测试
所有这些集都应该具有标准的源集结构。在项目中创建这些文件夹,并将包移动到相应的源集。
完成后,在以下行之前添加到build.gradle
dependency section
:
sourceSets {
integrationTest {
compileClasspath += main.output
runtimeClasspath += main.output
}
serviceTest {
compileClasspath += main.output
runtimeClasspath += main.output
}
}
configurations {
integrationTestCompile.extendsFrom testCompile
integrationTestRuntime.extendsFrom testRuntime
serviceTestCompile.extendsFrom testCompile
serviceTestRuntime.extendsFrom testRuntime
}
执行此操作后,您的IDE(我想您使用Idea(应该重新索引build.gradle
并识别源代码集。新源集中可能存在错误,因为它们看不到彼此的源。这是正确的,因为这些源集旨在独立运行,应该不是问题。
将dependencies
与适当的配置分开(可选(
默认情况下,serviceTest
和integrationTest
继承所有test
依赖项,但如果您需要将特定于特定配置的内容移出公共范围,则可以在此处执行此操作。
就我而言,WebDriver
非常重,除了集成测试之外,我在任何地方都不需要它。
dependencies {
// available for all scopes
testCompile "org.jetbrains.spek:spek-api:$spekVersion"
testRuntime "org.jetbrains.spek:spek-junit-platform-engine:$spekVersion"
testCompile "org.junit.platform:junit-platform-launcher:$junitPlatformVersion"
// compiles only for integrationTest
integrationTestCompile "org.seleniumhq.selenium:selenium-java:3.11.0"
integrationTestCompile "org.seleniumhq.selenium.fluent:fluent-selenium:1.19"
}
设置执行顺序
我们需要添加测试类型的 gradle 任务并对其进行设置。您可以为不同的测试任务设置不同的设置。
task serviceTest(type: Test) {
// Runs tests from src/serviceTest
testClassesDirs = sourceSets.serviceTest.output.classesDirs
classpath = sourceSets.serviceTest.runtimeClasspath
}
// Setup serviceTest task
serviceTest {
// Uncomment this if you need to skip tests from the set after first failure. Since Gradle 4.6
//failFast = true
// Enable some logging
testLogging {
events "PASSED", "FAILED", "SKIPPED"
}
// Enable JUnit5 tests
useJUnitPlatform {
}
}
对集成测试执行相同的操作。
最后,设置依赖项和执行顺序:
// Make service tests run during gradle check
check.dependsOn serviceTest
check.dependsOn integrationTest
// Make service tests run after unit tests
serviceTest.mustRunAfter test
// Make integration tests run after service tests
integrationTest.mustRunAfter serviceTest
结论
您将获得:
- 严格顺序运行的
Unit -> Service -> Integration
测试套件链; - 如果您在一个测试套件中遇到测试失败(无论
failFast
选项如何(,其余测试套件将不会运行并浪费资源; - 能够在执行
gradle <task>
内从控制台单独运行每个套件。
其他资源:
- 下面是使用
Spek
实现此设置的示例build.gradle
- gradle 4.6 版本的发行说明介绍了许多与测试相关的东西。
使用 IntelliJ 时要考虑的另一件事,并且它与新源代码集存在依赖问题,请将其添加到您的 build.gradle 中:
apply plugin: 'idea'
idea {
module {
testSourceDirs += project.sourceSets.unitTest.kotlin.srcDirs
testSourceDirs += project.sourceSets.unitTest.resources.srcDirs
testSourceDirs += project.sourceSets.integrationTest.kotlin.srcDirs
testSourceDirs += project.sourceSets.integrationTest.resources.srcDirs
testSourceDirs += project.sourceSets.functionalTest.kotlin.srcDirs
testSourceDirs += project.sourceSets.functionalTest.resources.srcDirs
}
}