JVM 測試套件外掛程式
JVM 測試套件外掛程式(外掛程式 ID:jvm-test-suite
)提供 DSL 和 API,以在基於 JVM 的專案中將多個自動化測試群組建模為測試套件。測試套件旨在按其目的分組,並且可以具有單獨的相依性並使用不同的測試框架。
例如,此外掛程式可用於定義一組整合測試,這些測試的執行時間可能比單元測試長得多,並且具有不同的環境要求。
JVM 測試套件外掛程式是一個孵化中的 API,並且在未來的版本中可能會發生變更。 |
用法
此外掛程式由 java
外掛程式自動應用,但如果需要,也可以額外顯式應用。如果沒有應用 JVM 語言外掛程式,則無法使用此外掛程式,因為它依賴於 java
外掛程式的幾個慣例。
plugins {
java
`jvm-test-suite`
}
plugins {
id 'java'
id 'jvm-test-suite'
}
此外掛程式將以下物件新增至專案
-
用於配置測試套件的
testing
擴充功能(類型:TestingExtension)。
當與 Java 外掛程式 一起使用時
-
名為
test
的測試套件(類型:JvmTestSuite)。 -
test
SourceSet。 -
幾個從
test
SourceSet 名稱衍生的配置:testImplementation
、testCompileOnly
、testRuntimeOnly
-
由名為
test
的任務支援的單個測試套件目標。
test
任務、SourceSet 和衍生的配置在名稱和功能上與先前 Gradle 版本中使用的那些相同。
配置
請參閱 API 文件中的 TestingExtension 類別。
宣告額外的測試套件
testing {
suites { (1)
val test by getting(JvmTestSuite::class) { (2)
useJUnitJupiter() (3)
}
register<JvmTestSuite>("integrationTest") { (4)
dependencies {
implementation(project()) (5)
}
targets { (6)
all {
testTask.configure {
shouldRunAfter(test)
}
}
}
}
}
}
tasks.named("check") { (7)
dependsOn(testing.suites.named("integrationTest"))
}
testing {
suites { (1)
test { (2)
useJUnitJupiter() (3)
}
integrationTest(JvmTestSuite) { (4)
dependencies {
implementation project() (5)
}
targets { (6)
all {
testTask.configure {
shouldRunAfter(test)
}
}
}
}
}
}
tasks.named('check') { (7)
dependsOn(testing.suites.integrationTest)
}
1 | 配置此專案的所有測試套件。 |
2 | 配置內建的 test 套件。此套件是為了向後相容性而自動建立的。您必須指定要使用的測試框架才能執行這些測試(例如,JUnit 4、JUnit Jupiter)。此套件是唯一將自動存取生產原始碼的 implementation 相依性的套件,所有其他套件都必須顯式宣告這些相依性。 |
3 | 宣告此測試套件使用 JUnit Jupiter。框架的相依性會自動包含在內。即使需要 JUnit4,也始終需要顯式配置內建的 test 套件。 |
4 | 定義一個名為 integrationTest 的新套件。請注意,除了內建的 test 套件之外的所有其他套件,依慣例都將像調用 useJUnitJupiter() 一樣工作。除非您希望變更為另一個框架,否則您不必在這些額外的套件上顯式配置測試框架。 |
5 | 將專案的生產程式碼的相依性新增至 integrationTest 套件目標。依慣例,只有內建的 test 套件才會自動具有專案生產程式碼的相依性。 |
6 | 配置此套件的所有目標。依慣例,測試套件目標與其他 Test 任務沒有關係。此範例顯示,較慢的整合測試套件目標應在 test 套件的所有目標完成後執行。 |
7 | 配置 check 任務以取決於所有 integrationTest 目標。依慣例,測試套件目標與 check 任務不關聯。 |
在上述配置的建置上調用 check
任務應顯示類似於以下的輸出
> Task :compileJava > Task :processResources NO-SOURCE > Task :classes > Task :jar > Task :compileTestJava > Task :processTestResources NO-SOURCE > Task :testClasses > Task :test > Task :compileIntegrationTestJava > Task :processIntegrationTestResources NO-SOURCE > Task :integrationTestClasses > Task :integrationTest > Task :check BUILD SUCCESSFUL in 0s 6 actionable tasks: 6 executed
請注意,integrationTest
測試套件在 test
測試套件完成後才會執行。
配置內建的 test
套件
testing {
suites {
val test by getting(JvmTestSuite::class) {
useTestNG() (1)
targets {
all {
testTask.configure { (2)
// set a system property for the test JVM(s)
systemProperty("some.prop", "value")
options { (3)
val options = this as TestNGOptions
options.preserveOrder = true
}
}
}
}
}
}
}
testing { (1)
suites {
test {
useTestNG() (1)
targets {
all {
testTask.configure { (2)
// set a system property for the test JVM(s)
systemProperty 'some.prop', 'value'
options { (3)
preserveOrder = true
}
}
}
}
}
}
}
1 | 宣告 test 測試套件使用 TestNG 測試框架。 |
2 | 延遲配置套件所有目標的測試任務;請注意 testTask 的返回類型為 TaskProvider<Test> 。 |
3 | 配置更詳細的測試框架選項。options 將是 org.gradle.api.tasks.testing.TestFrameworkOptions 的子類別,在本例中它是 org.gradle.api.tasks.testing.testng.TestNGOptions 。 |
配置測試套件的相依性
testing {
suites {
val test by getting(JvmTestSuite::class) { (1)
dependencies {
// Note that this is equivalent to adding dependencies to testImplementation in the top-level dependencies block
implementation("org.assertj:assertj-core:3.21.0") (2)
annotationProcessor("com.google.auto.value:auto-value:1.9") (3)
}
}
}
}
testing {
suites {
test { (1)
dependencies {
// Note that this is equivalent to adding dependencies to testImplementation in the top-level dependencies block
implementation 'org.assertj:assertj-core:3.21.0' (2)
annotationProcessor 'com.google.auto.value:auto-value:1.9' (3)
}
}
}
}
1 | 配置內建的 test 測試套件。 |
2 | 將 assertj 函式庫新增至測試的編譯和執行階段類別路徑。測試套件中的 dependencies 區塊已針對該測試套件進行範圍界定。測試套件具有一致的名稱,您可以在此區塊中使用該名稱來宣告 implementation 、compileOnly 、runtimeOnly 和 annotationProcessor 相依性,而不必知道配置的全局名稱。 |
3 | 將 Auto Value 注釋處理器新增至套件的注釋處理器類別路徑,以便在編譯測試時將其執行。 |
配置測試套件的相依性以參考專案輸出
dependencies {
api("com.google.guava:guava:30.1.1-jre") (1)
implementation("com.fasterxml.jackson.core:jackson-databind:2.13.3") (2)
}
testing {
suites {
val integrationTest by registering(JvmTestSuite::class) {
dependencies {
implementation(project()) (3)
}
}
}
}
dependencies {
api 'com.google.guava:guava:30.1.1-jre' (1)
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.3' (2)
}
testing {
suites {
integrationTest(JvmTestSuite) {
dependencies {
implementation project() (3)
}
}
}
}
1 | 新增一個生產相依性,該相依性用作函式庫公共 API 的一部分。 |
2 | 新增一個生產相依性,該相依性僅在內部使用,並且不會作為此專案的公共類別的一部分公開。 |
3 | 配置一個新的測試套件,該套件將 project() 相依性新增至套件的編譯和執行階段類別路徑。此相依性提供對專案輸出以及在其 api 和 compileOnlyApi 配置上宣告的任何相依性的存取。 |
配置測試套件的原始碼目錄
testing {
suites {
val integrationTest by registering(JvmTestSuite::class) { (1)
sources { (2)
java { (3)
setSrcDirs(listOf("src/it/java")) (4)
}
}
}
}
}
testing {
suites {
integrationTest(JvmTestSuite) { (1)
sources { (2)
java { (3)
srcDirs = ['src/it/java'] (4)
}
}
}
}
}
1 | 宣告和配置名為 integrationTest 的套件。SourceSet 和合成的 Test 任務將基於此名稱。 |
2 | 配置測試套件的 sources 。 |
3 | 配置測試套件的 java SourceDirectorySet。 |
4 | 覆寫 srcDirs 屬性,將傳統的 src/integrationTest/java 位置替換為 src/it/java 。 |
為測試套件配置 Test
任務
testing {
suites {
val integrationTest by getting(JvmTestSuite::class) {
targets {
all { (1)
testTask.configure {
setMaxHeapSize("512m") (2)
}
}
}
}
}
}
testing {
suites {
integrationTest {
targets {
all { (1)
testTask.configure {
maxHeapSize = '512m' (2)
}
}
}
}
}
}
1 | 配置透過宣告同名套件而建立的 integrationTest 任務。 |
2 | 配置 Test 任務屬性。 |
與測試套件目標關聯的 Test
任務也可以直接按名稱配置。不必透過測試套件 DSL 進行配置。
在多個測試套件之間共享配置
有幾種方法可以在多個測試套件之間共享配置,以避免重複相依性或其他配置。每種方法都是靈活性與聲明式與命令式配置樣式之間的權衡。
-
在
suites
容器上使用configureEach
方法來以相同方式配置每個測試套件。 -
將
withType
和matching
與configureEach
一起使用,以篩選測試套件並配置它們的子集。 -
將配置區塊提取到本機變數,並僅將其應用於所需的測試套件。
方法 1:使用 configureEach
這是跨每個測試套件共享配置的最直接方法。配置將應用於每個測試套件。
testing {
suites {
withType<JvmTestSuite> { (1)
useJUnitJupiter()
dependencies { (2)
implementation("org.mockito:mockito-junit-jupiter:4.6.1")
}
}
(3)
val integrationTest by registering(JvmTestSuite::class)
val functionalTest by registering(JvmTestSuite::class) {
dependencies { (4)
implementation("org.apache.commons:commons-lang3:3.11")
}
}
}
}
testing {
suites {
configureEach { (1)
useJUnitJupiter()
dependencies { (2)
implementation('org.mockito:mockito-junit-jupiter:4.6.1')
}
}
(3)
integrationTest(JvmTestSuite)
functionalTest(JvmTestSuite) {
dependencies { (4)
implementation('org.apache.commons:commons-lang3:3.11')
}
}
}
}
1 | 配置每個 JVM 測試套件 |
2 | 提供所有測試套件要共享的相依性 |
3 | 定義將在建立時配置的其他測試套件 |
4 | 新增特定於 functionalTest 測試套件的相依性 |
方法 2:使用 withType
、matching
和 configureEach
此方法新增篩選命令,以僅將配置應用於測試套件的子集,如名稱所識別。
testing {
suites {
withType(JvmTestSuite::class).matching { it.name in listOf("test", "integrationTest") }.configureEach { (1)
useJUnitJupiter()
dependencies {
implementation("org.mockito:mockito-junit-jupiter:4.6.1")
}
}
val integrationTest by registering(JvmTestSuite::class)
val functionalTest by registering(JvmTestSuite::class) {
useJUnit() (2)
dependencies { (3)
implementation("org.apache.commons:commons-lang3:3.11")
}
}
}
}
testing {
suites {
withType(JvmTestSuite).matching { it.name in ['test', 'integrationTest'] }.configureEach { (1)
useJUnitJupiter()
dependencies {
implementation('org.mockito:mockito-junit-jupiter:4.6.1')
}
}
integrationTest(JvmTestSuite)
functionalTest(JvmTestSuite) {
useJUnit() (2)
dependencies { (3)
implementation('org.apache.commons:commons-lang3:3.11')
}
}
}
}
1 | 配置每個符合給定條件的 JVM 測試套件 |
2 | 為 functionalTest 測試套件使用不同的測試框架 |
3 | 新增特定於 functionalTest 測試套件的相依性 |
方法 3:提取自訂配置區塊
此方法是最靈活的,但也是最命令式的。
testing {
suites {
val applyMockito = { suite: JvmTestSuite -> (1)
suite.useJUnitJupiter()
suite.dependencies {
implementation("org.mockito:mockito-junit-jupiter:4.6.1")
}
}
/* This is the equivalent of:
val test by getting(JvmTestSuite::class) {
applyMockito(this)
}
*/
val test by getting(JvmTestSuite::class, applyMockito) (2)
/* This is the equivalent of:
val integrationTest by registering(JvmTestSuite::class)
applyMockito(integrationTest.get())
*/
val integrationTest by registering(JvmTestSuite::class, applyMockito) (3)
val functionalTest by registering(JvmTestSuite::class) {
useJUnit()
dependencies {
implementation("org.apache.commons:commons-lang3:3.11")
}
}
}
}
testing {
suites {
def applyMockito = { suite -> (1)
suite.useJUnitJupiter()
suite.dependencies {
implementation('org.mockito:mockito-junit-jupiter:4.6.1')
}
}
/* This is the equivalent of:
test {
applyMockito(this)
}
*/
test(applyMockito) (2)
/* This is the equivalent of:
integrationTest(JvmTestSuite)
applyMockito(integrationTest)
*/
integrationTest(JvmTestSuite, applyMockito) (3)
functionalTest(JvmTestSuite) {
useJUnit()
dependencies {
implementation('org.apache.commons:commons-lang3:3.11')
}
}
}
}
1 | 定義一個閉包,它採用單個 JvmTestSuite 參數並對其進行配置 |
2 | 將閉包應用於測試套件,使用預設 (test ) 測試套件 |
3 | 將配置閉包應用於其宣告之外的測試套件的替代方法,使用 integrationTest 測試套件 |
JvmTestSuite 和 Test 任務類型上類似方法之間的差異
JvmTestSuite 的實例具有方法 useJUnit() 和 useJUnitJupiter(),它們在名稱上與 Test 任務類型上的方法相似:useJUnit() 和 useJUnitPlatform()。但是,存在重要差異。
與 Test 任務上的方法不同,JvmTestSuite 方法執行兩個額外的配置步驟
-
JvmTestSuite#useJUnit()、#useJUnitJupiter() 和其他特定於框架的方法會自動將相關的測試框架函式庫應用於套件目標的編譯和執行階段類別路徑。請注意,重載方法(例如 JvmTestSuite#useJUnit(String) 和 #useJUnitJupiter(String))允許您提供框架相依性的特定版本。
-
JvmTestSuite#useJUnit() 和 #useJUnitJupiter() 會自動配置套件目標的 Test 任務,以使用指定的框架執行。
上述第一個配置範例 配置內建的 test
套件 中顯示了此行為的範例。
與 Test 任務不同,JvmTestSuite 上的上述方法不接受用於配置框架的閉包或動作。這些框架配置選項可以在個別目標上設定。 |
輸出變體
每個測試套件都會建立一個輸出變體,其中包含其測試執行結果。這些變體旨在供 測試報告彙總外掛程式 使用。
屬性將類似於以下內容。使用者可配置的屬性在範例下方突出顯示。
--------------------------------------------------
Variant testResultsElementsForTest (i)
--------------------------------------------------
Description = Directory containing binary results of running tests for the test Test Suite's test target.
Capabilities
- org.gradle.sample:list:1.0.2 (default capability)
Attributes
- org.gradle.category = verification
- org.gradle.testsuite.name = test (1)
- org.gradle.verificationtype = test-results
Artifacts
- build/test-results/test/binary (artifactType = directory)
1 | TestSuiteName 屬性;值衍生自 TestSuite#getName()。 |