在原生生態系統中進行測試是一個豐富的主題。有許多不同的測試函式庫和框架,以及許多不同的測試類型。所有這些都需要成為建置的一部分,無論它們的執行頻率高或低。本章專門解釋 Gradle 如何處理建置之間和建置內部的不同需求,並深入介紹它如何與 macOS 和 Linux 上的 XCTest 整合。
本章說明: - 如何控制測試的執行方式(測試執行) - 如何選擇要執行的特定測試(測試篩選) - 生成哪些測試報告以及如何影響此過程(測試報告) - Gradle 如何找到要運行的測試(測試偵測)
但首先,我們先來看看 Gradle 中原生測試的基本概念。
基本概念
Gradle 支援與 Swift 語言的 XCTest 測試框架深度整合,並圍繞 XCTest 工作類型展開。這會在 macOS 上使用 Xcode XCTest 或在 Linux 上使用 開源 Swift 核心函式庫替代方案 執行一組測試案例,並整理結果。然後,您可以透過 TestReport 工作類型的實例將這些結果轉換為報告。
為了運作,XCTest 工作類型需要三項資訊: - 在哪裡找到已建置的可測試套件(在 macOS 上)或可執行檔(在 Linux 上)(屬性:XCTest.getTestInstalledDirectory()) - 執行套件或可執行檔的執行腳本(屬性:XCTest.getRunScriptFile()) - 執行套件或可執行檔的工作目錄(屬性:XCTest.getWorkingDirectory())
當您使用 XCTest 外掛程式 時,您將自動獲得以下內容: - 類型為 SwiftXCTestSuite 的專用 xctest
擴充功能,用於配置測試組件及其變體 - 類型為 XCTest 的 xcTest
工作,用於執行這些單元測試 - 與主要組件的物件檔案連結的可測試套件或可執行檔
測試外掛程式會適當地配置所需的資訊。此外,它們還將 xcTest
或 run
工作附加到 check
生命周期工作。它還建立 testImplementation
相依性配置。僅測試編譯、連結和運行時需要的相依性可以添加到此配置中。xctest
腳本區塊的行為與 application
或 library
腳本區塊類似。
XCTest 工作有許多配置選項。我們將在本章的其餘部分介紹其中許多選項。
測試執行
Gradle 在單獨的(「forked」)程序中執行測試。
您可以透過 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 類型結合了來自多個測試工作的結果,並且需要聚合單個測試類別的結果。這表示如果給定的測試類別由多個測試工作執行,則測試報告將包含該類別的執行,但可能難以區分該類別的個別執行及其輸出。