Gradle sourceSets來源集
- Gradle
- Maven
1.概述
源代碼集為我們提供了一種在Gradle項目中構建源代碼的強大方法。
在本快速教程中,我們將了解如何使用它們。
2.默認來源集
在進入默認值之前,讓我們首先解釋什麼是源集。顧名思義,源集代表源文件的邏輯分組。
我們將介紹Java項目的配置,但是這些概念也適用於其他Gradle項目類型。
2.1 默認項目佈局
讓我們從一個簡單的項目結構開始:
source-sets
├── src
│ ├── main
│ │ └── java
│ │ ├── SourceSetsMain.java
│ │ └── SourceSetsObject.java
│ └── test
│ └── java
│ └── SourceSetsTest.java
└── build.gradle
現在讓我們看一下build.gradle
:
apply plugin : "java"
description = "Source Sets example"
test {
testLogging {
events "passed", "skipped", "failed"
}
}
dependencies {
implementation('org.apache.httpcomponents:httpclient:4.5.12')
testImplementation('junit:junit:4.12')
}
Java插件假定**src/main/java
和src/test/java
為默認源目錄**.
讓我們設計一個簡單的實用程序任務:
task printSourceSetInformation(){
doLast{
sourceSets.each { srcSet ->
println "["+srcSet.name+"]"
print "-->Source directories: "+srcSet.allJava.srcDirs+"\n"
print "-->Output directories: "+srcSet.output.classesDirs.files+"\n"
println ""
}
}
}
我們在這裡僅打印一些源集屬性。我們總是可以查看完整的JavaDoc以獲得更多信息。
讓我們運行它,看看會得到什麼:
$ ./gradlew printSourceSetInformation
> Task :source-sets:printSourceSetInformation
[main]
-->Source directories: [.../source-sets/src/main/java]
-->Output directories: [.../source-sets/build/classes/java/main]
[test]
-->Source directories: [.../source-sets/src/test/java]
-->Output directories: [.../source-sets/build/classes/java/test]
注意,我們有兩個默認的源集: main
和test
。
2.2 默認配置
**Java插件還會自動為我們創建一些默認的Gradle配置**。
它們遵循特殊的命名約定: <sourceSetName><configurationName>
。
我們使用它們在build.gradle
聲明依賴項:
dependencies {
implementation('org.apache.httpcomponents:httpclient:4.5.12')
testImplementation('junit:junit:4.12')
}
注意,我們指定了implementation
而不是mainImplementation
。這是命名約定的例外。
默認情況下, testImplementation
配置擴展implementation
並繼承其所有依賴項和輸出。
讓我們改進幫助程序任務,看看這是關於什麼的:
task printSourceSetInformation(){
doLast{
sourceSets.each { srcSet ->
println "["+srcSet.name+"]"
print "-->Source directories: "+srcSet.allJava.srcDirs+"\n"
print "-->Output directories: "+srcSet.output.classesDirs.files+"\n"
print "-->Compile classpath:\n"
srcSet.compileClasspath.files.each {
print " "+it.path+"\n"
}
println ""
}
}
}
讓我們看一下輸出:
[main]
// same output as before
-->Compile classpath:
.../httpclient-4.5.12.jar
.../httpcore-4.4.13.jar
.../commons-logging-1.2.jar
.../commons-codec-1.11.jar
[test]
// same output as before
-->Compile classpath:
.../source-sets/build/classes/java/main
.../source-sets/build/resources/main
.../httpclient-4.5.12.jar
.../junit-4.12.jar
.../httpcore-4.4.13.jar
.../commons-logging-1.2.jar
.../commons-codec-1.11.jar
.../hamcrest-core-1.3.jar
test
源集在其編譯類路徑中main
的輸出,還包括其依賴項。
接下來,讓我們創建我們的單元測試:
public class SourceSetsTest {
@Test
public void whenRun_ThenSuccess() {
SourceSetsObject underTest = new SourceSetsObject("lorem","ipsum");
assertThat(underTest.getUser(), is("lorem"));
assertThat(underTest.getPassword(), is("ipsum"));
}
}
在這裡,我們測試一個簡單的POJO,該POJO存儲兩個值。我們可以直接使用它,因為**main
輸出在我們的test
類路徑中**。
接下來,讓我們從Gradle中運行它:
./gradlew clean test
> Task :source-sets:test
com.baeldung.test.SourceSetsTest > whenRunThenSuccess PASSED
3.自定義來源集
到目前為止,我們已經看到了一些明智的默認設置。但是,實際上,我們經常需要自定義源集,尤其是對於集成測試。
那是因為我們可能只想在集成測試類路徑上擁有特定的測試庫。我們還可能希望獨立於單元測試執行它們。
3.1 定義自定義源集
讓我們為集成測試設計一個單獨的源目錄:
source-sets
├── src
│ └── main
│ ├── java
│ │ ├── SourceSetsMain.java
│ │ └── SourceSetsObject.java
│ ├── test
│ │ └── SourceSetsTest.java
│ └── itest
│ └── SourceSetsITest.java
└── build.gradle
接下來,讓**我們使用sourceSets
構造build.gradle
**進行配置:
sourceSets {
itest {
java {
}
}
}
dependencies {
implementation('org.apache.httpcomponents:httpclient:4.5.12')
testImplementation('junit:junit:4.12')
}
// other declarations omitted
注意,我們沒有指定任何自定義目錄。這是因為我們的文件夾與新的源集( itest
)的名稱匹配。
我們可以**srcDirs
屬性包含的目錄**:
sourceSets{
itest {
java {
srcDirs("src/itest")
}
}
}
從一開始就還記得我們的幫助任務嗎?讓我們重新運行它,看看它顯示了什麼:
$ ./gradlew printSourceSetInformation
> Task :source-sets:printSourceSetInformation
[itest]
-->Source directories: [.../source-sets/src/itest/java]
-->Output directories: [.../source-sets/build/classes/java/itest]
-->Compile classpath:
.../source-sets/build/classes/java/main
.../source-sets/build/resources/main
[main]
// same output as before
[test]
// same output as before
3.2 分配源集特定的依存關係
還記得默認配置嗎?現在,我們還為itest
源集獲取了一些配置。
讓我們使用itestImplementation
分配一個新的依賴項:
dependencies {
implementation('org.apache.httpcomponents:httpclient:4.5.12')
testImplementation('junit:junit:4.12')
itestImplementation('com.google.guava:guava:29.0-jre')
}
這僅適用於集成測試。
讓我們修改之前的測試並將其添加為集成測試:
public class SourceSetsItest {
@Test
public void givenImmutableList_whenRun_ThenSuccess() {
SourceSetsObject underTest = new SourceSetsObject("lorem", "ipsum");
List someStrings = ImmutableList.of("Baeldung", "is", "cool");
assertThat(underTest.getUser(), is("lorem"));
assertThat(underTest.getPassword(), is("ipsum"));
assertThat(someStrings.size(), is(3));
}
}
為了能夠運行它,我們需要定義一個使用已編譯輸出的自定義測試任務:
// source sets declarations
// dependencies declarations
task itest(type: Test) {
description = "Run integration tests"
group = "verification"
testClassesDirs = sourceSets.itest.output.classesDirs
classpath = sourceSets.itest.runtimeClasspath
}
這些聲明在配置階段**進行評估。結果,它們的順序很重要**。
例如,在聲明此聲明之前,我們無法引用itest
讓我們看看如果運行測試會發生什麼:
$ ./gradlew clean itest
// some compilation issues
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':source-sets:compileItestJava'.
> Compilation failed; see the compiler error output for details.
與之前的運行不同,這次我們遇到編譯錯誤。所以發生了什麼事?
這個新的源集將創建一個獨立的配置。
換句話說, itestImplementation
不會繼承JUnit
依賴關係,也不會獲取main
的輸出。
讓我們在Gradle配置中解決此問題:
sourceSets{
itest {
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
java {
}
}
}
// dependencies declaration
configurations {
itestImplementation.extendsFrom(testImplementation)
itestRuntimeOnly.extendsFrom(testRuntimeOnly)
}
現在,讓我們重新運行集成測試:
$ ./gradlew clean itest
> Task :source-sets:itest
com.baeldung.itest.SourceSetsItest > givenImmutableList_whenRun_ThenSuccess PASSED
測試通過。
3.3 Eclipse IDE處理
到目前為止,我們已經看到瞭如何直接使用Gradle處理源集。但是,大多數時候,我們將使用IDE(例如Eclipse)。
導入項目時,會遇到一些編譯問題:
但是,如果我們從Gradle運行集成測試,則不會出現任何錯誤:
$ ./gradlew clean itest
> Task :source-sets:itest
com.baeldung.itest.SourceSetsItest > givenImmutableList_whenRun_ThenSuccess PASSED
所以發生了什麼事?在這種情況下, guava
依賴項屬於itestImplementation
。
不幸的是, Eclipse Buildship Gradle插件不能很好地處理這些自定義配置。
讓我們**build.gradle
修復此**問題:
apply plugin: "eclipse"
// previous declarations
eclipse {
classpath {
plusConfigurations+=[configurations.itestCompileClasspath]
}
}
讓我們解釋一下我們在這裡做了什麼。我們將配置附加到Eclipse類路徑中。
如果我們刷新項目,則編譯問題就消失了。
但是,這種方法有一個缺點:IDE不能區分配置。
這意味著我們可以輕鬆地在test
源中guava
(我們特別想避免這種情況)。
4 結論
在本教程中,我們介紹了Gradle源集的基礎。
然後,我們解釋了定制源集如何工作以及如何在Eclipse中使用它們。