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 / javasrc / 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]
주의

: 우리는 두 개의 기본 소스 세트가 테스트를

.

2.2. 기본 구성

 

Java 플러그인은 또한 일부 기본 Gradle 구성자동으로 생성 합니다 .

특수 명명 규칙 인 <sourceSetName> <configurationName>을 따릅니다 .

이를 사용하여

build.gradle

에서 종속성을 선언합니다 .
dependencies { 
    implementation('org.apache.httpcomponents:httpclient:4.5.12') 
    testImplementation('junit:junit:4.12') 
}
mainImplementation 대신

구현

을 지정 합니다 . 이것은 명명 규칙에 대한 예외입니다.

기본적으로 testImplementation 구성은 구현을 확장 하고 모든 종속성 및 출력을 상속합니다

.도우미 작업을 개선하고 이것이 무엇인지 살펴 보겠습니다.
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

테스트

소스 세트의 출력 포함

본체를

그 컴파일 클래스 경로도 그 종속성을 포함한다.다음으로 단위 테스트를 만들어 보겠습니다.
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를 테스트합니다. 때문에 우리는 직접 사용할 수 있습니다 메인 출력이 우리에 테스트 클래스 패스 .다음으로 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 
다음의이하자

우리의 그것을 구성 build.gradle 은 Using sourceSets의 구조를

:
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.
이전 실행과 달리 이번에는 컴파일 오류가 발생합니다. 그래서 무슨 일이 있었나요?이 새로운 소스 세트는 독립적 인 구성을 생성합니다.즉,

itestImplementationJUnit 종속성을 상속하지 않으며 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
그래서 무슨 일이 있었나요? 이 경우

구아바

종속성은 

itestImplementation에 속합니다

.불행히도

Eclipse Buildship Gradle 플러그인은 이러한 사용자 지정 구성을 잘 처리하지 못합니다

.build.gradle

에서이 문제를 해결

하겠습니다 .
apply plugin: "eclipse"

// previous declarations

eclipse {
    classpath {
        plusConfigurations+=[configurations.itestCompileClasspath] 
    } 
}
여기서 우리가 무엇을했는지 설명해 봅시다. Eclipse 클래스 경로에 구성을 추가했습니다.프로젝트를 새로 고치면 컴파일 문제가 사라집니다.그러나이

방법에는 단점이

있습니다. IDE는 구성을 구분하지 않습니다.즉, 테스트  소스 에서 구아바  를 

쉽게 가져올 수 있습니다

(특히 피하고 싶었습니다).

4. 결론

 
이 튜토리얼에서는 Gradle 소스 세트의 기본 사항을 다뤘습니다.그런 다음 사용자 정의 소스 세트가 작동하는 방식과 Eclipse에서이를 사용하는 방법에 대해 설명했습니다.평소처럼

GitHub

에서 전체 소스 코드 찾을 수 있습니다 .