Swift 测试支持与 配置缓存 不兼容。 |
原生生态系统中的测试是一个丰富的主题。有许多不同的测试库和框架,以及许多不同类型的测试。所有这些都需要成为构建的一部分,无论它们是频繁执行还是不频繁执行。本章专门介绍 Gradle 如何处理构建之间和构建内部的不同需求,并重点介绍了它如何在 macOS 和 Linux 上与 XCTest 集成。
它解释了:- 控制测试运行方式的方法(测试执行)- 如何选择要运行的特定测试(测试过滤)- 生成的测试报告以及如何影响该过程(测试报告)- Gradle 如何找到要运行的测试(测试检测)
但首先,我们来看看 Gradle 中原生测试的基础知识。
基础知识
Gradle 支持与 Swift 语言的 XCTest 测试框架深度集成,并围绕 XCTest 任务类型。这使用 Xcode XCTest 在 macOS 上或 开源 Swift 核心库替代方案 在 Linux 上运行一组测试用例,并整理结果。然后,您可以通过 TestReport 任务类型的实例将这些结果转换为报告。
为了运行,XCTest 任务类型需要三条信息:- 在哪里找到已构建的可测试捆绑包(在 macOS 上)或可执行文件(在 Linux 上)(属性:XCTest.getTestInstalledDirectory())- 用于执行捆绑包或可执行文件的运行脚本(属性:XCTest.getRunScriptFile())- 用于执行捆绑包或可执行文件的工作目录(属性:XCTest.getWorkingDirectory())
当您使用 XCTest 插件 时,您将自动获得以下内容: - 一个专门的 xctest
扩展,类型为 SwiftXCTestSuite,用于配置测试组件及其变体 - 一个 xcTest
任务,类型为 XCTest,用于运行这些单元测试 - 一个与主组件的目标文件链接的可测试捆绑包或可执行文件
测试插件会适当地配置所需的信息。此外,它们将 xcTest
或 run
任务附加到 check
生命周期任务。它还会创建 testImplementation
依赖项配置。仅在测试编译、链接和运行时需要的依赖项可以添加到此配置中。xctest
脚本块的行为类似于 application
或 library
脚本块。
The XCTest 任务有许多配置选项。我们在本章的剩余部分介绍了其中许多选项。
测试执行
Gradle 在一个单独的(“分叉”)进程中执行测试。
您可以通过 XCTest 任务上的多个属性来控制测试进程的启动方式,包括以下内容
ignoreFailures
- 默认值:false-
如果此属性为
true
,则 Gradle 将在测试完成后继续执行项目的构建,即使其中一些测试失败。请注意,默认情况下,两种任务类型始终执行它检测到的所有测试,无论此设置如何。 testLogging
- 默认值:未设置-
此属性表示一组控制记录哪些测试事件以及在哪个级别上的选项。您还可以通过此属性配置其他日志记录行为。设置 TestLoggingContainer 以获取更多详细信息。
有关所有可用配置选项的详细信息,请参阅 XCTest。
测试过滤
运行测试套件的子集是一个常见的需求,例如,当您修复错误或开发新的测试用例时。Gradle 提供过滤功能来实现这一点。您可以根据以下条件选择要运行的测试
-
一个简单的类名或方法名,例如
SomeTest
、SomeTest.someMethod
-
“*”通配符匹配
您可以在构建脚本中或通过 --tests
命令行选项启用过滤。以下是一些每次构建运行时应用的过滤器的示例
xctest {
binaries.configureEach {
runTask.get().filter.includeTestsMatching("SomeIntegTest.*") // or `"Testing.SomeIntegTest.*"` on macOS
}
}
xctest {
binaries.configureEach {
runTask.get().configure {
// include all tests from test class
filter.includeTestsMatching "SomeIntegTest.*" // or `"Testing.SomeIntegTest.*"` on macOS
}
}
}
有关在构建脚本中声明过滤器更多详细信息和示例,请参阅 TestFilter 参考。
命令行选项对于执行单个测试方法特别有用。也可以提供多个 --tests
选项,所有这些选项的模式都将生效。以下部分包含使用命令行选项的几个示例。
测试过滤目前仅支持与 XCTest 兼容的过滤器。这意味着相同的过滤器在 macOS 和 Linux 上会有所不同。在 macOS 上,需要将捆绑包基本名称添加到过滤器前面,例如 TestBundle.SomeTest 、TestBundle.SomeTest.someMethod 。有关有效过滤模式的更多信息,请参见下面的 简单名称模式 部分。
|
以下部分介绍了简单类/方法名称的特定情况。
简单名称模式
Gradle 支持简单类名或类名 + 方法名测试过滤。例如,以下命令行运行 SomeTestClass
测试用例中的所有测试或仅运行其中的一个测试。
# Executes all tests in SomeTestClass
gradle xcTest --tests SomeTestClass
# or `gradle xcTest --tests TestBundle.SomeTestClass` on macOS
# Executes a single specified test in SomeTestClass
gradle xcTest --tests TestBundle.SomeTestClass.someSpecificMethod
# or `gradle xcTest --tests TestBundle.SomeTestClass.someSpecificMethod` on macOS
您还可以将命令行中定义的过滤器与 持续构建 相结合,以便在每次更改生产或测试源文件后立即重新执行测试子集。以下命令在每次更改触发测试运行时执行 ‘SomeTestClass’ 测试类中的所有测试。
gradle test --continuous --tests SomeTestClass
测试报告
默认情况下,XCTest 任务会生成以下结果。
-
HTML 测试报告
-
与 Ant JUnit 报告任务兼容的 XML 测试结果 - 许多其他工具(例如 CI 服务器)都支持这种格式
-
XCTest
任务用来生成其他格式的有效二进制结果格式
在大多数情况下,您将使用标准 HTML 报告,该报告会自动包含来自 XCTest
任务的结果。
还有一个独立的 TestReport 任务类型,您可以使用它来生成自定义 HTML 测试报告。它只需要一个 destinationDir
值和要包含在报告中的测试结果。以下是一个示例,它为所有子项目中的单元测试生成一个组合报告。
plugins {
id("xctest")
}
extensions.configure<SwiftXCTestSuite>() {
binaries.configureEach {
// Disable the test report for the individual test task
runTask.get().reports.html.required = false
}
}
configurations.create("binaryTestResultsElements") {
isCanBeResolved = false
isCanBeConsumed = true
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION))
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named("test-report-data"))
}
tasks.withType<XCTest>() {
outgoing.artifact(binaryResultsDirectory)
}
}
plugins {
`reporting-base`
}
val testReportData by configurations.creating {
isCanBeConsumed = false
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION))
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named("test-report-data"))
}
}
dependencies {
testReportData(project(":core"))
testReportData(project(":util"))
}
tasks.register<TestReport>("testReport") {
destinationDirectory = reporting.baseDirectory.dir("allTests")
// Use test results from testReportData configuration
testResults.from(testReportData)
}
plugins {
id 'xctest'
}
xctest {
binaries.configureEach {
runTask.get().configure {
// Disable the test report for the individual test task
reports.html.required = false
}
}
}
// Share the test report data to be aggregated for the whole project
configurations {
binaryTestResultsElements {
canBeResolved = false
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION))
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, 'test-report-data'))
}
tasks.withType(XCTest).configureEach {
outgoing.artifact(it.binaryResultsDirectory)
}
}
}
// A resolvable configuration to collect test reports data
plugins {
id 'reporting-base'
}
configurations {
testReportData {
canBeConsumed = false
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION))
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, 'test-report-data'))
}
}
}
dependencies {
testReportData project(':core')
testReportData project(':util')
}
tasks.register('testReport', TestReport) {
destinationDirectory = reporting.baseDirectory.dir('allTests')
// Use test results from testReportData configuration
testResults.from(configurations.testReportData)
}
在此示例中,我们使用约定插件 myproject.xctest-conventions
将项目的测试结果公开给 Gradle 的 变体感知依赖项管理引擎。
该插件声明了一个可消耗的 binaryTestResultsElements
配置,它代表 test
任务的二进制测试结果。在聚合项目的构建文件中,我们声明了 testReportData
配置,并依赖于我们要聚合结果的所有项目。Gradle 将自动从每个子项目中选择二进制测试结果变体,而不是项目的 jar 文件。最后,我们添加了一个 testReport
任务,它从 testResultsDirs
属性聚合测试结果,该属性包含从 testReportData
配置解析的所有二进制测试结果。
请注意,TestReport 类型组合了来自多个测试任务的结果,需要聚合单个测试类的结果。这意味着如果给定的测试类由多个测试任务执行,那么测试报告将包含该类的执行,但可能难以区分该类的单个执行及其输出。