在本地生态系统中进行测试是一个丰富的主题. 有许多不同的测试库和框架,以及许多不同类型的测试. 无论它们是频繁执行还是不频繁执行,所有这些都需要成为构建的一部分. 本章致力于说明Gradle如何处理内部版本之间以及内部版本之间的不同要求,并广泛介绍了Gradle如何与macOS和Linux上的XCTest集成.

它解释了:-控制测试运行方式的方法(测试执行)-如何选择要运行的特定测试(测试过滤)-生成了哪些测试报告以及如何影响过程(测试报告)-Gradle如何找到要运行的测试运行(测试检测)

但是首先,我们看一下Gradle中本机测试的基础.

The basics

Gradle支持与Swift语言的XCTest测试框架进行深度集成,并围绕XCTest任务类型展开. 这将使用macOS上的Xcode XCTest或Linux上的开源Swift核心库替代品来运行一系列测试用例,并整理结果. 然后,您可以通过TestReport任务类型的实例将这些结果转换为报告.

为了进行操作, XCTest任务类型需要三条信息:-在哪里找到构建的可测试包(在macOS上)或可执行文件(在Linux上)(属性: XCTest.getTestInstalledDirectory() )-用于执行包的运行脚本或可执行文件(属性: XCTest.getRunScriptFile() )-执行捆绑或可执行文件的工作目录(属性: XCTest.getWorkingDirectory()

当你使用XCTest插件您将自动获得如下: -一个专用xctest类型的扩展名SwiftXCTestSuite配置测试组件及其变种-一个xcTest类型的任务XCTest运行这些单元测试-可测试软件包或可执行文件链接主要组件的目标文件

测试插件会适当配置所需的信息. 此外,它们xcTestrun任务附加到check生命周期任务. 它还创建了testImplementation依赖项配置. 只能将测试编译,链接和运行时所需的依赖项添加到此配置中. xctest脚本块的行为类似于applicationlibrary脚本块.

XCTest任务具有许多配置选项. 在本章的其余部分中,我们将讨论其中的许多内容.

Test execution

Gradle在单独的("分叉")过程中执行测试.

您可以通过XCTest任务上的几个属性来控制如何启动测试过程,包括以下内容:

ignoreFailures - default: false

如果此属性为true ,则即使测试中的某些失败,Gradle也会在测试完成后继续进行项目的构建. 请注意,默认情况下,无论使用哪种设置,这两种任务类型始终执行它检测到的每个测试.

testLogging - default: not set

此属性表示一组选项,用于控制记录哪些测试事件以及在什么级别进行记录. 您还可以通过此属性配置其他日志记录行为. 设置TestLoggingContainer以获得更多详细信息.

有关所有可用配置选项的详细信息,请参见XCTest .

Test filtering

运行测试套件的子集是常见的要求,例如,当您修复错误或开发新的测试用例时. Gradle为此提供了过滤. 您可以根据以下条件选择要运行的测试:

  • 一个简单的类名或方法名,例如SomeTestSomeTest.someMethod

  • '*'通配符匹配

您可以在构建脚本中或通过--tests命令行选项启用过滤. 这是每次构建运行时都会应用的一些过滤器的示例:

例子1.筛选每个构建的测试
build.gradle
xctest {
    binaries.configureEach {
        runTask.get().configure {
            // include all tests from test class
            filter.includeTestsMatching "SomeIntegTest.*" // or `"Testing.SomeIntegTest.*"` on macOS
        }
    }
}
build.gradle.kts
xctest {
    binaries.configureEach {
        runTask.get().filter.includeTestsMatching("SomeIntegTest.*") // or `"Testing.SomeIntegTest.*"` on macOS
    }
}

有关在构建脚本中声明过滤器的更多详细信息和示例,请参见TestFilter参考.

命令行选项对于执行单个测试方法特别有用. 也可以提供多个--tests选项,所有选项都会生效. 以下各节提供了几个使用命令行选项的示例.

目前,测试过滤仅支持XCTest兼容过滤器. 这意味着同一过滤器在macOS和Linux之间会有所不同. 在macOS上,捆绑软件的基本名称必须位于过滤器之前,例如TestBundle.SomeTestTestBundle.SomeTest.someMethod .有关有效过滤模式的更多信息,请参见下面的" 简单名称模式"部分.

以下部分介绍简单类/方法名称的具体情况.

Simple name pattern

Gradle支持简单的类名,或类名+方法名的测试过滤. 例如,以下命令行运行SomeTestClass测试用例中的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

Test reporting

XCTest任务默认情况下会生成以下结果:

  • HTML测试报告

  • XML测试结果的格式与Ant JUnit报告任务兼容-许多其他工具(例如CI服务器)都支持该格式

  • XCTest任务用于生成其他格式的结果的有效二进制格式

在大多数情况下,您将使用标准HTML报告,该报告自动包含XCTest任务的结果.

还有一个独立的TestReport任务类型,可用于生成自定义HTML测试报告. 它所需要的只是destinationDir的值以及要包含在报告中的测试结果. 这是一个示例,可为所有子项目的单元测试生成组合报告:

Example 2. Combine test reports from all subprojects
build.gradle
subprojects {
    apply plugin: 'xctest'

    xctest {
        binaries.configureEach {
            runTask.get().configure {
                // Disable the test report for the individual test task
                reports.html.enabled = false
            }
        }
    }
}

tasks.register('testReport', TestReport) {
    destinationDir = file("$buildDir/reports/allTests")

    // Include the results from the XCTest tasks in all subprojects
    reportOn subprojects.collect {
        it.tasks.withType(XCTest)
    }
}
build.gradle.kts
subprojects {
    apply(plugin = "xctest")

    extensions.configure<SwiftXCTestSuite>() {
        binaries.configureEach {
            // Disable the test report for the individual test task
            runTask.get().reports.html.isEnabled = false
        }
    }
}

tasks.register<TestReport>("testReport") {
    destinationDir = file("$buildDir/reports/allTests")

    // Include the results from the `xcTest` task in all subprojects
    reportOn(subprojects.map { it.tasks.withType<XCTest>() })
}

您应该注意, TestReport类型组合了多个测试任务的结果,并且需要汇总单个测试类的结果. 这意味着给定的测试类由多个测试任务执行,然后测试报告将包含该类的执行,但是很难区分该类的各个执行及其输出.