Gradle Java 插件

2022-08-03 14:58 更新

Java 插件向一個(gè)項(xiàng)目添加了 Java 編譯、 測試和 bundling 的能力。它是很多其他 Gradle 插件的基礎(chǔ)服務(wù)。

用法

要使用 Java 插件,請?jiān)跇?gòu)建腳本中加入:

使用 Java 插件

build.gradle

apply plugin: 'java'  

源集

Java 插件引入了一個(gè)源集的概念。一個(gè)源集只是一組用于編譯并一起執(zhí)行的源文件。這些源文件可能包括 Java 源代碼文件和資源文件。其他有一些插件添加了在源集里包含 Groovy 和 Scala 的源代碼文件的能力。一個(gè)源集有一個(gè)相關(guān)聯(lián)的編譯類路徑和運(yùn)行時(shí)類路徑。

源集的一個(gè)用途是,把源文件進(jìn)行邏輯上的分組,以描述它們的目的。例如,你可能會使用一個(gè)源集來定義一個(gè)集成測試套件,或者你可能會使用單獨(dú)的源集來定義你的項(xiàng)目的 API 和實(shí)現(xiàn)類。

Java 插件定義了兩個(gè)標(biāo)準(zhǔn)的源集,分別是 main 和 test。main 源集包含你產(chǎn)品的源代碼,它們將被編譯并組裝成一個(gè) JAR 文件。test 源集包含你的單元測試的源代碼,它們將被編譯并使用 JUnit 或 TestNG 來執(zhí)行。

任務(wù)

Java 插件向你的項(xiàng)目添加了大量的任務(wù),如下所示。

表 23.1. Java 插件-任務(wù)

任務(wù)名稱 依賴于 類型 描述
compileJava 產(chǎn)生編譯類路徑中的所有任務(wù)。這包括了用于jar任務(wù)。 JavaCompile 使用 javac 編譯產(chǎn)品中的 Java 源文件。
processResources - Copy 把生產(chǎn)資源文件拷貝到生產(chǎn)的類目錄中。
classes processResources。一些插件添加了額外的編譯任務(wù)。 Task 組裝生產(chǎn)的類目錄。
compileTestJava compile,再加上所有能產(chǎn)生測試編譯類路徑的任務(wù)。 JavaCompile 使用 javac 編譯 Java 的測試源文件。
processTestResources - Copy 把測試的資源文件拷貝到測試的類目錄中。
testClasses processTestResources。一些插件添加了額外的測試編譯任務(wù)。 Task 組裝測試的類目錄。
jar compile Jar 組裝 JAR 文件
javadoc compile Javadoc 使用 Javadoc 生成生產(chǎn)的 Java 源代碼的API文檔
test compileTest,再加上所有產(chǎn)生測試運(yùn)行時(shí)類路徑的任務(wù)。 Test 使用 JUnit 或 TestNG運(yùn)行單元測試。
uploadArchives 使用jar。 Upload 使用archives配置上傳包括 JAR 文件的構(gòu)件。
clean - Delete 刪除項(xiàng)目的 build 目錄。
TaskName - Delete 刪除由指定的任務(wù)所產(chǎn)生的輸出文件。例如, jar任務(wù)中所創(chuàng)建的 JAR 文件,test任務(wù)所創(chuàng)建的測試結(jié)果。

對于每個(gè)你添加到該項(xiàng)目中的源集,Java 插件將添加以下的編譯任務(wù):

表 23.2. Java 插件-源集任務(wù)

任務(wù)名稱 依賴于 類型 描述
SourceSetJava 所有產(chǎn)生源集編譯類路徑的任務(wù)。 JavaCompile 使用 javac 編譯給定的源集中的 Java 源文件。
SourceSetResources - Copy 把給定的源集的資源文件拷貝到類目錄中。
sourceSetClasses SourceSetResources。某些插件還為源集添加了額外的編譯任務(wù)。 Task 組裝給定源集的類目錄。

Java 插件還增加了大量的任務(wù)構(gòu)成該項(xiàng)目的生命周期:

表 23.3. Java 插件-生命周期任務(wù)

任務(wù)名稱 依賴于 類型 描述
assemble 項(xiàng)目中的所有歸檔項(xiàng)目,包括jar任務(wù)。某些插件還向項(xiàng)目添加額外的歸檔任務(wù)。 Task 組裝項(xiàng)目中所有的歸類文件。
check 項(xiàng)目中的所有核查項(xiàng)目,包括test任務(wù)。某些插件還向項(xiàng)目添加額外的核查任務(wù)。 Task 執(zhí)行項(xiàng)目中所有的核查任務(wù)。
build assemble Task 執(zhí)行項(xiàng)目的完事構(gòu)建。
buildNeeded build任務(wù)。 Task 執(zhí)行項(xiàng)目本身及它所依賴的其他所有項(xiàng)目的完整構(gòu)建。
buildDependents build任務(wù)。 Task 執(zhí)行項(xiàng)目本身及依賴它的其他所有項(xiàng)目的完整構(gòu)建。
ConfigurationName 使用配置ConfigurationName生成構(gòu)件的任務(wù)。 Task 組裝指定配置的構(gòu)件。該任務(wù)由Base插件添加,并由Java插件隱式實(shí)現(xiàn)。
ConfigurationName 使用配置ConfigurationName上傳構(gòu)件的任務(wù)。 Upload 組裝并上傳指定配置的構(gòu)件。該任務(wù)由Base插件添加,并由Java插件隱式實(shí)現(xiàn)。

uploadConfigurationName 使用配置 ConfigurationName 上傳構(gòu)件的任務(wù)。 Upload 組裝并上傳指定配置的構(gòu)件。該任務(wù)由 Base 插件添加,并由 Java 插件隱式實(shí)現(xiàn)。 下圖顯示了這些任務(wù)之間的關(guān)系。

圖23.1. Java 插件 ??- 任務(wù)

Java 插件 ??- 任務(wù)

項(xiàng)目布局

Java 插件會假定如下所示的項(xiàng)目布局。這些目錄都不需要一定存在,或者是里面有什么內(nèi)容。Java 插件將會進(jìn)行編譯,不管它發(fā)現(xiàn)什么,并處理缺少的任何東西。

表 23.4. Java 插件-默認(rèn)項(xiàng)目布局

目錄 意義
src/main/java 產(chǎn)品的Java源代碼
src/main/resources 產(chǎn)品的資源
src/test/java Java 測試源代碼
src/test/resources 測試資源
sourceSet/java 給定的源集的Java源代碼
sourceSet/resources 給定的源集的資源

更改項(xiàng)目布局

你可以通過配置適當(dāng)?shù)脑醇?,來配置?xiàng)目的布局。這一點(diǎn)將在以下各節(jié)中詳細(xì)討論。這里是如何更改 main Java 和資源源目錄的一個(gè)簡短的例子。

自定義 Java 源代碼布局

build.gradle

sourceSets {
    main {
        java {
            srcDir 'src/java'
        }
        resources {
            srcDir 'src/resources'
        }
    }
}  

依賴管理

Java 插件向項(xiàng)目添加了許多依賴配置,如下圖所示。它對一些任務(wù)指定了這些配置,如 compileJava 和 test。

表23.5. Java插件 ??- 依賴配置

名稱 繼承自 在哪些任務(wù)中使用 意義
compile - compileJava 編譯時(shí)依賴
runtime compile - 運(yùn)行時(shí)依賴
testCompile compile compileTestJava 用于編譯測試的其他依賴
testRuntime runtime, testCompile test 只用于運(yùn)行測試的其他依賴
archives - uploadArchives 由本項(xiàng)目生產(chǎn)的構(gòu)件(如jar包)。
default runtime - 本項(xiàng)目上的默認(rèn)項(xiàng)目依賴配置。包含本項(xiàng)目運(yùn)行時(shí)所需要的構(gòu)件和依賴。

圖23.2. Java 插件 ??- 依賴配置

Java 插件 ??- 依賴配置

對于每個(gè)你添加到項(xiàng)目中的源集,Java 插件都會添加以下的依賴配置:

表23.6. Java 插件 ??- 源集依賴配置

名稱 繼承自 在哪些任務(wù)中使用 意義
sourceSetCompile - compileSourceSetJava 給定源集的編譯時(shí)依賴
sourceSetRuntime sourceSetCompile - 給定源集的運(yùn)行時(shí)依賴

常規(guī)屬性

Java 插件向項(xiàng)目添加了許多常規(guī)屬性,如下圖所示。您可以在構(gòu)建腳本中使用這些屬性,就像它們是 project 對象的屬性一樣。

表23.7. Java 插件 ??- 目錄屬性

屬性名稱 類型 默認(rèn)值 描述
reportsDirName String reports 相對于build目錄的目錄名稱,報(bào)告將生成到此目錄。
reportsDir File (read-only) reportsDirName 報(bào)告將生成到此目錄。
testResultsDirName String test-results 相對于build目錄的目錄名稱,測試報(bào)告的.xml文件將生成到此目錄。
testResultsDir File (read-only) testResultsDirName 測試報(bào)告的.xml文件將生成到此目錄。
testReportDirName String tests 相對于build目錄的目錄名稱,測試報(bào)告將生成到此目錄。
testReportDir File (read-only) testReportDirName 測試報(bào)告生成到此目錄。
libsDirName String libs 相對于build目錄的目錄名稱,類庫將生成到此目錄中。
libsDir File (read-only) libsDirName 類庫將生成到此目錄中。
distsDirName String distributions 相對于build目錄的目錄名稱,發(fā)布的文件將生成到此目錄中。
distsDir File (read-only) distsDirName 要發(fā)布的文件將生成到此目錄。
docsDirName String docs 相對于build目錄的目錄名稱,文檔將生成到此目錄。
docsDir File (read-only) docsDirName 要生成文檔的目錄。
dependencyCacheDirName String dependency-cache 相對于build目錄的目錄名稱,該目錄用于緩存源代碼的依賴信息。
dependencyCacheDir File (read-only) dependencyCacheDirName 該目錄用于緩存源代碼的依賴信息。

表 23.8. Java 插件 - 其他屬性

屬性名稱 類型 默認(rèn)值 描述
sourceSets SourceSetContainer (read-only) 非空 包含項(xiàng)目的源集。
sourceCompatibility JavaVersion. 可以使用字符串或數(shù)字來設(shè)置,例如1.5。 當(dāng)前JVM所使用的值 當(dāng)編譯Java源代碼時(shí)所使用的Java版本兼容性。
targetCompatibility JavaVersion. 可以使用字符串或數(shù)字來設(shè)置,例如1.5 sourceCompatibility 要生成的類的 Java 版本。
archivesBaseName String projectName 像JAR或ZIP文件這樣的構(gòu)件的basename
manifest Manifest 一個(gè)空的清單 要包括的所有 JAR 文件的清單。

這些屬性由 JavaPluginConvention, BasePluginConvention 和 ReportingBasePluginConvention 這些類型的常規(guī)對象提供。

使用源集

你可以使用 sourceSets 屬性訪問項(xiàng)目的源集。這是項(xiàng)目的源集的容器,它的類型是 SourceSetContainer。除此之后,還有一個(gè) sourceSets {}的腳本塊,可以傳入一個(gè)閉包來配置源集容器。源集容器的使用方式幾乎與其他容器一樣,例如 tasks。

訪問源集

build.gradle

// Various ways to access the main source set
println sourceSets.main.output.classesDir
println sourceSets['main'].output.classesDir
sourceSets {
    println main.output.classesDir
}
sourceSets {
    main {
        println output.classesDir
    }
}
// Iterate over the source sets
sourceSets.all {
    println name
}  

要配置一個(gè)現(xiàn)有的源集,你只需使用上面的其中一種訪問方法來設(shè)置源集的屬性。這些屬性將在下文中進(jìn)行介紹。下面是一個(gè)配置 main 的 Java 和資源目錄的例子:

配置源集的源代碼目錄

build.gradle

sourceSets {
    main {
        java {
            srcDir 'src/java'
        }
        resources {
            srcDir 'src/resources'
        }
    }
}  

源集屬性

下表列出了一些重要的源集屬性。你可以在 SourceSet 的 API 文檔中查看更多的詳細(xì)信息。

表 23.9. Java 插件 - 源集屬性

屬性名稱 類型 默認(rèn)值 描述
name String (read-only) 非空 用來確定一個(gè)源集的源集名稱。
output SourceSetOutput (read-only) 非空 源集的輸出文件,包含它編譯過的類和資源。
output.classesDir File name 要生成的該源集的類的目錄。
output.resourcesDir File name 要生成的該源集的資源的目錄。
compileClasspath FileCollection SourceSet 配置。 該類路徑在編譯該源集的源文件時(shí)使用。
runtimeClasspath FileCollection SourceSet 配置。 該類路徑在執(zhí)行該源集的類時(shí)使用。
java SourceDirectorySet (read-only) 非空 該源集的Java源文件。僅包含Java源文件目錄里的.java文件,并排除其他所有文件。
java.srcDirs Set<File> name/java] 該源目錄包含了此源集的所有Java源文件。
resources SourceDirectorySet (read-only) 非空 此源集的資源文件。僅包含資源文件,并且排除在資源源目錄中找到的所有 .java文件。其他插件,如Groovy 插件,會從該集合中排除其他類型的文件。
resources.srcDirs Set<File> name/resources] 該源目錄包含了此源集的資源文件。
allJava SourceDirectorySet (read-only) java 該源集的所有.java 文件。有些插件,如Groovy 插件,會從該集合中增加其他的Java源文件。
allSource SourceDirectorySet (read-only) resources + java 該源集的所有源文件。包含所有的資源文件和Java源文件。有些插件,如Groovy 插件,會從該集合中增加其他的源文件。

定義新的源集

要定義一個(gè)新的源集,你只需在 sourceSets {}塊中引用它。下面是一個(gè)示例:

定義一個(gè)源集

build.gradle

sourceSets {
    intTest
}  

當(dāng)您定義一個(gè)新的源集時(shí),Java 插件會為該源集添加一些依賴配置,如表 23.6,“Java 插件 - 源集依賴項(xiàng)配置”所示。你可以使用這些配置來定義源集的編譯和運(yùn)行時(shí)的依賴。

定義源集依賴

build.gradle

sourceSets {
    intTest
}
dependencies {
    intTestCompile 'junit:junit:4.11'
    intTestRuntime 'org.ow2.asm:asm-all:4.0'
}  

Java 插件還添加了大量的任務(wù),用于組裝源集的類,如表 23.2,“Java 插件 - 源設(shè)置任務(wù)”所示。例如,對于一個(gè)被叫做 intTest 的源集,你可以運(yùn)行 gradle intTestClasses 來編譯 int 測試類。

編譯源集

gradle intTestClasses的輸出結(jié)果

> gradle intTestClasses
:compileIntTestJava
:processIntTestResources
:intTestClasses
BUILD SUCCESSFUL
Total time: 1 secs  

一些源集的范例

添加一個(gè)包含了源集的類的 JAR 包

示例 23.8. 為一個(gè)源集裝配一個(gè)JAR文件

build.gradle

task intTestJar(type: Jar) {
    from sourceSets.intTest.output
}  

為一個(gè)源集生成 Javadoc:

示例 23.9. 為一個(gè)源集生成 Javadoc:

build.gradle

task intTestJavadoc(type: Javadoc) {
    source sourceSets.intTest.allJava
}  

添加一個(gè)測試套件以運(yùn)行一個(gè)源集里的測試

示例 23.10. 運(yùn)行源集里的測試

build.gradle

task intTest(type: Test) {
    testClassesDir = sourceSets.intTest.output.classesDir
    classpath = sourceSets.intTest.runtimeClasspath
}  

Javadoc

Javadoc 任務(wù)是 Javadoc 的一個(gè)實(shí)例。它支持核心的 javadoc 參數(shù)選項(xiàng),以及在 Javadoc 可執(zhí)行文件的參考文檔中描述的標(biāo)準(zhǔn) doclet 參數(shù)選項(xiàng)。對于支持的 Javadoc 參數(shù)選項(xiàng)的完整列表,請參考下面的類的 API 文檔: CoreJavadocOptions 和StandardJavadocDocletOptions。

表 23.10. Java 插件 - Javadoc 屬性

任務(wù)屬性 類型 默認(rèn)值
classpath FileCollection sourceSets.main.output + sourceSets.main.compileClasspath
source FileTree. sourceSets.main.allJava
destinationDir File docsDir/javadoc
title String project的名稱和版本

清理

clean 任務(wù)是 Delete 的一個(gè)實(shí)例。它只是刪除由其 dir 屬性表示的目錄。

表 23.11. Java 插件 - Clean 性能

任務(wù)屬性 類型 默認(rèn)值
dir File buildDir

資源

Java 插件使用 Copy 任務(wù)進(jìn)行資源的處理。它為該 project 里的每個(gè)源集添加一個(gè)實(shí)例。你可以在16.6章節(jié),“復(fù)制文件”中找到關(guān)于 copy 任務(wù)的更多信息。

表 23.12. Java 插件-ProcessResources 屬性

任務(wù)屬性 類型 默認(rèn)值
srcDirs Object. sourceSet.resources
destinationDir  16.1 章節(jié),“查找文件”中所講到的任何一種方式來設(shè)置。 sourceSet.output.resourcesDir

CompileJava

Java 插件為該 project 里的每個(gè)源集添加一個(gè) JavaCompile 實(shí)例。一些最常見的配置選項(xiàng)如下所示。

表 23.13. Java 插件- Compile 屬性

任務(wù)屬性 類型 默認(rèn)值
classpath FileCollection sourceSet.compileClasspath
source FileTree sourceSet.java
destinationDir File. sourceSet.output.classesDir

compile 任務(wù)委派了 Ant 的 javac 任務(wù)。將 options.useAnt 設(shè)置為 false 將繞過 Ant 任務(wù),而激活 Gradle 的直接編譯器集成。在未來的 Gradle 版本中,將把它作為默認(rèn)設(shè)置。

默認(rèn)情況下,Java 編譯器在 Gradle 過程中運(yùn)行。將 options.fork 設(shè)置為 true 將會使編譯出現(xiàn)在一個(gè)單獨(dú)的進(jìn)程中。在 Ant javac 任務(wù)中,這意味著將會為每一個(gè) compile 任務(wù)fork 一個(gè)新的進(jìn)程,而這將會使編譯變慢。相反,Gradle 的直接編譯器集成 (見上文) 將盡可能多地重用相同的編譯器進(jìn)程。在這兩種情況下,使用 options.forkOptions 指定的所有fork 選項(xiàng)都將得到重視。

Test

test 任務(wù)是 Test 的一個(gè)實(shí)例。它會自動(dòng)檢測和執(zhí)行 test 源集中的所有單元測試。測試執(zhí)行完成后,它還會生成一份報(bào)告。同時(shí)支持 JUnit 和 TestNG。可以看一看Test的完整的 API。

測試執(zhí)行

測試在單獨(dú)的 JVM 中執(zhí)行,與 main 構(gòu)建進(jìn)程隔離。Test 任務(wù)的 API 可以讓你控制什么時(shí)候開始。

有大量的屬性用于控制測試進(jìn)程的啟動(dòng)。這包括系統(tǒng)屬性、 JVM 參數(shù)和使用的 Java 可執(zhí)行文件。

你可以指定是否要并行運(yùn)行你的測試。Gradle 通過同時(shí)運(yùn)行多個(gè)測試進(jìn)程來提供并行測試的執(zhí)行。每個(gè)測試進(jìn)程會依次執(zhí)行一個(gè)單一的測試,所以你一般不需要對你的測試做任何的配置來利用這一點(diǎn)。 MaxParallelForks 屬性指定在給定的時(shí)間可以運(yùn)行的測試進(jìn)程的最大數(shù)。它的默認(rèn)值是 1,也就是說,不并行執(zhí)行測試。

測試進(jìn)程程會為其將 org.gradle.test.worker 系統(tǒng)屬性設(shè)置為一個(gè)唯一標(biāo)識符,這個(gè)標(biāo)識符可以用于文件名稱或其他資源標(biāo)識符。

你可以指定在執(zhí)行了一定數(shù)量的測試類之后,重啟那個(gè)測試進(jìn)程。這是一個(gè)很有用的替代方案,讓你的測試進(jìn)程可以有很大的堆內(nèi)存。forkEvery 屬性指定了要在測試進(jìn)程中執(zhí)行的測試類的最大數(shù)。默認(rèn)是每個(gè)測試進(jìn)程中執(zhí)行的測試數(shù)量不限。

該任務(wù)有一個(gè) ignoreFailures 屬性,用以控制測試失敗時(shí)的行為。test 會始終執(zhí)行它檢測到的每一個(gè)測試。如果 ignoreFailures 為 false,并且有測試不通過,那它會停止繼續(xù)構(gòu)建。IgnoreFailures 的默認(rèn)值為 false。

testLogging 屬性可以配置哪些測試事件需要記錄,并且使用什么樣的日志級別。默認(rèn)情況下,對于每個(gè)失敗的測試都只會打印一個(gè)簡潔的消息。請參閱 TestLoggingContainer,查看如何把你的測試日志打印調(diào)整為你的偏好設(shè)置。

調(diào)試

test 任務(wù)提供了一個(gè) Test.getDebug()屬性,可以設(shè)置為啟動(dòng),使 JVM 在執(zhí)行測試之前,等待一個(gè) debugger 連接到它的 5005 端口上。

這也可以在調(diào)用時(shí)通過--debug-vm task 選項(xiàng)進(jìn)行啟用。

測試過濾

從 Gradle 1.10 開始,可以根據(jù)測試的名稱模式,只包含指定的測試。過濾,相對于測試類的包含或排除,是一個(gè)不同的機(jī)制。它將在接下來的段落中進(jìn)行描述(-Dtest.single, test.include 和 friends)。后者基于文件,比如測試實(shí)現(xiàn)類的物理位置。file-level 的測試選擇不支持的很多有趣的情況,都可以用 test-level 過濾來做到。以下這些場景中,有一些 Gradle 現(xiàn)在就可以處理,而有一些則將在未來得到實(shí)現(xiàn):

  • 在指定的測試的方法級別上進(jìn)行過濾;執(zhí)行單個(gè)測試方法
  • 基于自定義注解(以后實(shí)現(xiàn))進(jìn)行過濾
  • 基于測試層次結(jié)構(gòu)進(jìn)行過濾 ;執(zhí)行所有繼承了某一基類(以后實(shí)現(xiàn)) 的測試
  • 基于一些自定義的運(yùn)行時(shí)的規(guī)則進(jìn)行過濾,例如某個(gè)系統(tǒng)屬性或一些靜態(tài)的特定值(以后實(shí)現(xiàn))

測試過濾功能具有以下的特征:

  • 支持完整的限定類名稱或完整的限定的方法名稱,例如“org.gradle.SomeTest”、“org.gradle.SomeTest.someMethod”
  • 通配符 “*” 支付匹配任何字符
  • 提供了“--tests”的命令行選項(xiàng),以方便地設(shè)置測試過濾器。這對“單一測試方法的執(zhí)行”的經(jīng)典用例特別有用。當(dāng)使用該命令行選項(xiàng)選項(xiàng)時(shí),在構(gòu)建腳本中聲明的列入過濾器的測試將會被忽略。
  • Gradle 盡最大努力對有著特定的測試框架 API 的局限的測試進(jìn)行過濾。一些高級的、 綜合的測試可能不完全符合過濾條件。然而,絕大多數(shù)的測試和用例都會被很好地處理。
  • 測試過濾將會取代基于文件的測試選擇。后者可能在將來會被完全地取代掉。我們將會繼續(xù)改進(jìn)測試過濾的 API,并添加更多種類的過濾器。

在構(gòu)建腳本中過濾測試

build.gradle

test {
    filter {
        //include specific method in any of the tests
        includeTestsMatching "*UiCheck"
        //include all tests from package
        includeTestsMatching "org.gradle.internal.*"
        //include all integration tests
        includeTestsMatching "*IntegTest"
    }
}  

有關(guān)更多的詳細(xì)信息和示例,請參閱 TestFilter 的文檔。

使用命令行選項(xiàng)的一些示例:

  • gradle test --tests org.gradle.SomeTest.someSpecificFeature
  • gradle test --tests *SomeTest.someSpecificFeature
  • gradle test --tests *SomeSpecificTest
  • gradle test --tests all.in.specific.package*
  • gradle test --tests *IntegTest
  • gradle test --tests IntegTestui*
  • gradle someTestTask --tests UiTest someOtherTestTask --tests WebTest*ui

通過系統(tǒng)屬性執(zhí)行單一的測試

這種機(jī)制已經(jīng)被上述的“測試過濾”所取代。 設(shè)置一個(gè) taskName.single = testNamePattern 的系統(tǒng)屬性將會只執(zhí)行匹配 testNamePattern 的那些測試。這個(gè) taskName 可以是一個(gè)完整的多項(xiàng)目路徑,比如“sub1:sub2:test”,或者僅是一個(gè)任務(wù)名稱。testNamePattern 將用于形成一個(gè)“*/testNamePattern.class” 的包含模式。如果這個(gè)模式無法找到任何測試,那么將會拋出一個(gè)異常。這是為了使你不會誤以為測試通過。如果執(zhí)行了一個(gè)以上的子項(xiàng)目的測試,該模式會被應(yīng)用于每一個(gè)子項(xiàng)目中。如果在一個(gè)特定的子項(xiàng)目中,找不到測試用例,那么將會拋出異常。在這種情況下你可以使用路徑標(biāo)記法的模式,這樣該模式就會只應(yīng)用于特定的子項(xiàng)目的測試任務(wù)中?;蛘吣憧梢灾付ㄒ獔?zhí)行的任務(wù)的完整限定名稱。你還可以指定多個(gè)模式。示例:

  • gradle -Dtest.single=ThisUniquelyNamedTest test
  • gradle -Dtest.single=a/b/ test
  • gradle -DintegTest.single=*IntegrationTest integTest
  • gradle -Dtest.single=:proj1:test:Customer build
  • gradle -DintegTest.single=c/d/ :proj1:integTest

測試檢測

Test 任務(wù)通過檢查編譯過的測試類來檢測哪些類是測試類。默認(rèn)情況下它會掃描所有的.class 文件。您可以設(shè)置自定義的 includes 或 excludes,這樣就只有這些類才會被掃描。根據(jù)所使用的測試框架 (JUnit 或 TestNG),會使用不同的標(biāo)準(zhǔn)進(jìn)行測試類的檢測。

當(dāng)使用 JUnit 時(shí),我們掃描 JUnit 3 和 4 的測試類。如果滿足以下的任何一個(gè)條件,這個(gè)類就被認(rèn)為是一個(gè) JUnit 測試類:

  • 類或超類繼承自 TestCase 或 GroovyTestCase
  • 類或超類使用了 @RunWith 進(jìn)行注解
  • 類或超類含有一個(gè)帶 @Test 注解的方法

當(dāng)使用 TestNG 時(shí),我們掃描所有帶有 @Test 注解的方法。

請注意,抽象類不會被執(zhí)行。Gradle 還將掃描測試類路徑中的 jar 文件里的繼承樹。

如果你不想要使用測試類檢測,可以通過設(shè)置 scanForTestClasses 為 false 來禁用它。這將使test任務(wù)只使用 includes / excludes 來找到測試類。如果 scanForTestClasses 為disabled,并且沒有指定 include 或 exclude 模式,則使用各自的默認(rèn)值。對于 include 的默認(rèn)值是 "/*Tests.class", "*/Test.class",而對于exclude它的默認(rèn)值是 "/Abstract*.class"。

測試分組

JUnit 和 TestNG 可以對測試方法進(jìn)行復(fù)雜的分組。

為對 Junit 測試類和方法進(jìn)行分組,JUnit 4.8 引入了類別的概念。test 任務(wù)可以實(shí)現(xiàn)一個(gè)規(guī)范,讓你 include 和 exclude 想要的 JUnit 類別。

JUnit 類別

build.gradle

test {
    useJUnit {
        includeCategories 'org.gradle.junit.CategoryA'
        excludeCategories 'org.gradle.junit.CategoryB'
    }
}  

TestNG 框架有一個(gè)非常相似的概念。在 TestNG 中你可以指定不同的測試組。應(yīng)從測試執(zhí)行中 include 或 exclude 的測試組,可以在 test 任務(wù)中配置。

對 TestNG 測試分組

build.gradle

test {
    useTestNG {
        excludeGroups 'integrationTests'
        includeGroups 'unitTests'
    }
}  

測試報(bào)告

test 任務(wù)默認(rèn)情況下會生成以下結(jié)果。

  • 一個(gè) HTML 測試報(bào)告。
  • 與 Ant Junit report 任務(wù)兼容的 XML 格式的結(jié)果。這種格式可以被許多工具所支持,比如CI服務(wù)器。
  • 有效二進(jìn)制格式的結(jié)果。這個(gè)任務(wù)會從這些二進(jìn)制結(jié)果生成其他的結(jié)果。

您可以使用 Test.setTestReport()方法來禁用 HTML 測試報(bào)告。目前不能禁用其他的結(jié)果。

這里還有一個(gè)獨(dú)立的 TestReport 任務(wù)類型,它可以從一個(gè)或多個(gè) Test 任務(wù)實(shí)例生成的二進(jìn)制結(jié)果中生成 HTML 測試報(bào)告。要使用這個(gè)任務(wù)類型,你需要定義一個(gè) destinationDir 和要包含到報(bào)告的測試結(jié)果。這里是一個(gè)范例,從子項(xiàng)目的單元測試中生成一個(gè)聯(lián)合報(bào)告:

為多個(gè)子項(xiàng)目創(chuàng)建一個(gè)單元測試報(bào)告

build.gradle

subprojects {
    apply plugin: 'java'

    // Disable the test report for the individual test task
    test {
        reports.html.enabled = false
    }
}
task testReport(type: TestReport) {
    destinationDir = file("$buildDir/reports/allTests")
    // Include the results from the `test` task in all subprojects
    reportOn subprojects*.test
}  

你應(yīng)該注意到,TestReport 類型組合了多個(gè)測試任務(wù)的結(jié)果,并且需要聚合各個(gè)測試類的結(jié)果。這意味著,如果一個(gè)給定的測試類被多個(gè) test 任務(wù)所執(zhí)行,那么測試報(bào)告將包括那個(gè)類的所有執(zhí)行結(jié)果,但它難以區(qū)分那個(gè)類的每次執(zhí)行和它們的輸出。

TestNG 參數(shù)化方法和報(bào)告

TestNG 支持參數(shù)化測試方法,允許一個(gè)特定的測試方法使用不同的輸入執(zhí)行多次。Gradle 會在這個(gè)方法的執(zhí)行報(bào)告中包含進(jìn)它的參數(shù)值。

給定一個(gè)帶有兩個(gè)參數(shù),名為 aParameterizedTestMethod 參數(shù)化測試方法,它將使用名稱這個(gè)名稱進(jìn)行報(bào)告 :aParameterizedTestMethod(toStringValueOfParam1, toStringValueOfParam2)。這使得在特定的迭代過程,很容易確定參數(shù)值。

常規(guī)值

表 23.14. Java 插件 - test 屬性

任務(wù)屬性 類型 默認(rèn)值
testClassesDir File sourceSets.test.output.classesDir
classpath FileCollection sourceSets.test.runtimeClasspath
testResultsDir File testResultsDir
testReportDir File testReportDir
testSrcDirs List<File> sourceSets.test.java.srcDirs

Jar

Jar 任務(wù)創(chuàng)建一個(gè)包含類文件和項(xiàng)目資源的 JAR 文件。JAR 文件在 archives 依賴配置中被聲明為一個(gè)構(gòu)件。這意味著這個(gè) JAR 文件被包含在一個(gè)依賴它的項(xiàng)目的類路徑中。如果你把你的項(xiàng)目上傳到倉庫,這個(gè) JAR 文件會被聲明為依賴描述符的一部分。你可以在第16.8節(jié),“創(chuàng)建檔案”和第51章, 發(fā)布 artifact 中了解如何使用 archives 和配置 artifact。

Manifest

每個(gè) jar 或 war 對象都有一個(gè)單獨(dú)的 Manifest 實(shí)例的 manifest 屬性。當(dāng)生成 archive 時(shí),相應(yīng)的 MANIFEST.MF 文件也會被寫入進(jìn)去。

自定義的 MANIFEST.MF

build.gradle

jar {
    manifest {
        attributes("Implementation-Title": "Gradle", "Implementation-Version": version)
    }
}  

您可以創(chuàng)建一個(gè)單獨(dú)的 Manifest 實(shí)例。它可以用于共享兩個(gè) jar 包的 manifest 信息。

創(chuàng)建一個(gè) manifest 對象。

build.gradle

ext.sharedManifest = manifest {
    attributes("Implementation-Title": "Gradle", "Implementation-Version": version)
}
task fooJar(type: Jar) {
    manifest = project.manifest {
        from sharedManifest
    }
}  

你可以把其他的 manifest 合并到任何一個(gè) Manifest 對象中。其他的 manifest 可能使用文件路徑來描述,像上面的例子,使用對另一個(gè) Manifest 對象的引用。

指定 archive 的單獨(dú) MANIFEST.MF

build.gradle

task barJar(type: Jar) {
    manifest {
        attributes key1: 'value1'
        from sharedManifest, 'src/config/basemanifest.txt'
        from('src/config/javabasemanifest.txt', 'src/config/libbasemanifest.txt') {
            eachEntry { details ->
                if (details.baseValue != details.mergeValue) {
                    details.value = baseValue
                }
                if (details.key == 'foo') {
                    details.exclude()
                }
            }
        }
    }
}  

Manifest 會根據(jù)在 from 語句中所聲明的順序進(jìn)行合并。如果基本的 manifest 和要合并的 manifest 都定義了同一個(gè) key 的值,那么默認(rèn)情況下會采用要合并的 manifest 的值。你可以通過添加 eachEntry action 來完全自定義合并行為,它可以讓你對每一項(xiàng)生成的 manifest 訪問它的一個(gè) ManifestMergeDetails 實(shí)例。這個(gè)合并操作不會在 from 語句中就馬上被觸發(fā)。它是懶執(zhí)行的,不管是對于生成一個(gè) jar 包,還是調(diào)用了 writeTo 或者 effectiveManifest

你可以很輕松地把一個(gè) manifest 寫入磁盤中。

指定 archive 的單獨(dú) MANIFEST.MF

build.gradle

jar.manifest.writeTo("$buildDir/mymanifest.mf")  
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號