Kumpulan Sumber Gradle

1. Gambaran keseluruhan

Kumpulan sumber memberi kita kaedah yang kuat untuk menyusun kod sumber dalam projek Gradle kami.

Dalam tutorial ringkas ini, kita akan melihat cara menggunakannya.

2. Set Sumber Lalai

Sebelum melangkah ke tahap lalai, mari kita jelaskan terlebih dahulu set sumber apa. Seperti namanya, kumpulan sumber mewakili pengelompokan fail sumber logik .

Kami akan merangkumi konfigurasi projek Java, tetapi konsepnya juga berlaku untuk jenis projek Gradle yang lain.

2.1. Susun atur Projek Lalai

Mari mulakan dengan struktur projek yang mudah:

source-sets ├── src │ └── main │ ├── java │ │ ├── SourceSetsMain.java │ │ └── SourceSetsObject.java │ └── test │ └── SourceSetsTest.java └── build.gradle 

Sekarang mari kita lihat 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') }

Plugin Java menganggap src / main / java dan src / test / java sebagai direktori sumber lalai .

Mari buat tugas utiliti yang mudah:

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 "" } } }

Kami mencetak hanya beberapa sifat set sumber di sini. Kami sentiasa dapat memeriksa JavaDoc penuh untuk maklumat lebih lanjut.

Mari jalankan dan lihat apa yang kita dapat:

$ ./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] 

Perhatikan bahawa kita mempunyai dua set sumber lalai: utama dan ujian .

2.2. Konfigurasi Lalai

Plugin Java juga secara automatik membuat beberapa konfigurasi Gradle lalai untuk kami .

Mereka mengikuti konvensyen penamaan khas: .

Kami menggunakannya untuk menyatakan kebergantungan dalam build.gradle :

dependencies { implementation('org.apache.httpcomponents:httpclient:4.5.12') testImplementation('junit:junit:4.12') }

Perhatikan bahawa kita menentukan pelaksanaan dan bukannya mainImplementation . Ini adalah pengecualian dari konvensyen penamaan.

Secara lalai, konfigurasi testImplementation memperluas pelaksanaan dan mewarisi semua kebergantungan dan outputnya .

Mari tingkatkan tugas pembantu kami dan lihat apa ini:

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 "" } } }

Mari lihat outputnya:

[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

The ujian set sumber mengandungi output utama dalam classpath menyusun dan juga termasuk taklukan.

Seterusnya, mari buat ujian unit kami:

public class SourceSetsTest { @Test public void whenRun_ThenSuccess() { SourceSetsObject underTest = new SourceSetsObject("lorem","ipsum"); assertThat(underTest.getUser(), is("lorem")); assertThat(underTest.getPassword(), is("ipsum")); } }

Di sini kita menguji POJO ringkas yang menyimpan dua nilai. Kita boleh menggunakan ia secara langsung kerana yang utama output adalah dalam kita ujian classpath .

Seterusnya, mari kita jalankan ini dari Gradle:

./gradlew clean test > Task :source-sets:test com.baeldung.test.SourceSetsTest > whenRunThenSuccess PASSED 

3. Set Sumber Tersuai

Setakat ini, kami telah melihat beberapa lalai yang masuk akal. Walau bagaimanapun, dalam praktiknya, kita sering memerlukan set sumber khusus, terutama untuk ujian integrasi.

Ini kerana kami mungkin ingin mempunyai pustaka ujian khusus hanya pada jalan kelas ujian integrasi. Kami juga mungkin ingin melaksanakannya secara bebas daripada ujian unit.

3.1. Menentukan Set Sumber Tersuai

Mari buat direktori sumber yang berasingan untuk ujian integrasi kami:

source-sets ├── src │ └── main │ ├── java │ │ ├── SourceSetsMain.java │ │ └── SourceSetsObject.java │ ├── test │ │ └── SourceSetsTest.java │ └── itest │ └── SourceSetsITest.java └── build.gradle 

Seterusnya, mari konfigurasikannya di build.gradle kami menggunakan konstruk sourceSets :

sourceSets { itest { java { } } } dependencies { implementation('org.apache.httpcomponents:httpclient:4.5.12') testImplementation('junit:junit:4.12') } // other declarations omitted 

Perhatikan kami tidak menentukan direktori tersuai. Ini kerana folder kami sepadan dengan nama kumpulan sumber baru ( itest ).

Kami dapat menyesuaikan direktori apa yang disertakan dengan harta srcDirs :

sourceSets{ itest { java { srcDirs("src/itest") } } }

Ingat tugas penolong kita dari awal? Mari jalankan semula dan lihat apa yang dicetaknya:

$ ./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. Menetapkan Sumber Bergantung Bergantung

Ingat konfigurasi lalai? Kami kini mendapat beberapa konfigurasi untuk set sumber itest juga.

Mari gunakan itestImplementation untuk memberikan kebergantungan baru :

dependencies { implementation('org.apache.httpcomponents:httpclient:4.5.12') testImplementation('junit:junit:4.12') itestImplementation('com.google.guava:guava:29.0-jre') }

Yang ini hanya berlaku untuk ujian integrasi.

Mari ubah suai ujian sebelumnya dan tambahkan sebagai ujian integrasi:

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)); } }

Untuk dapat menjalankannya , kita perlu menentukan tugas ujian khusus yang menggunakan output yang disusun :

// source sets declarations // dependencies declarations task itest(type: Test) { description = "Run integration tests" group = "verification" testClassesDirs = sourceSets.itest.output.classesDirs classpath = sourceSets.itest.runtimeClasspath }

Deklarasi ini dinilai semasa fasa konfigurasi . Hasilnya, pesanan mereka penting .

For example, we cannot reference the itest source set in the task body before this is declared.

Let's see what happens if we run the test:

$ ./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.

Unlike the previous run, we get a compilation error this time. So what happened?

This new source set creates an independent configuration.

In other words, itestImplementation does not inherit the JUnit dependency, nor does it get the outputs of main.

Let's fix this in our Gradle configuration:

sourceSets{ itest { compileClasspath += sourceSets.main.output runtimeClasspath += sourceSets.main.output java { } } } // dependencies declaration configurations { itestImplementation.extendsFrom(testImplementation) itestRuntimeOnly.extendsFrom(testRuntimeOnly) }

Now let's rerun our integration test:

$ ./gradlew clean itest > Task :source-sets:itest com.baeldung.itest.SourceSetsItest > givenImmutableList_whenRun_ThenSuccess PASSED

The test passes.

3.3. Eclipse IDE Handling

We've seen so far how to work with source sets directly with Gradle. However, most of the time, we'll be using an IDE (such as Eclipse).

When we import the project, we get some compilation issues:

However, if we run the integrations test from Gradle, we get no errors:

$ ./gradlew clean itest > Task :source-sets:itest com.baeldung.itest.SourceSetsItest > givenImmutableList_whenRun_ThenSuccess PASSED

So what happened? In this case, the guava dependency belongs to itestImplementation.

Unfortunately, the Eclipse Buildship Gradle plugin does not handle these custom configurations very well.

Let's fix this in our build.gradle:

apply plugin: "eclipse" // previous declarations eclipse { classpath { plusConfigurations+=[configurations.itestCompileClasspath] } } 

Let's explain what we did here. We appended our configuration to the Eclipse classpath.

If we refresh the project, the compilation issues are gone.

However, there's a drawback to this approach: The IDE does not distinguish between configurations.

This means we can easily import guava in our test sources (which we specifically wanted to avoid).

4. Conclusion

In this tutorial, we covered the basics of Gradle source sets.

Then we explained how custom source sets work and how to use them in Eclipse.

As usual, we can find the complete source code over on GitHub.