모종닷컴

[Gradle] 특정 환경에 테스트 필터 적용하기 본문

Programming/Gradle

[Gradle] 특정 환경에 테스트 필터 적용하기

모종 2023. 5. 1. 14:39
반응형

현재 개인 프로젝트를 진행해보고 있는데요. 이런 니즈가 생겼습니다. 로컬에서 Gradle 빌드 태스크를 돌렸을 때 실행되지 않았으면 하는 테스트 코드가 있고, CI 환경에는 테스트 코드가 실행되었으면 좋겠습니다.

예를 들어 통합 테스트 코드가 있습니다. 보통 테스트 시 데이터베이스가 필요하다면 h2 같은 인메모리 데이터베이스를 사용할 수 있는데 저는 MySQL에 특화된 테스트 코드가 있어서 h2와 같은 인메모리 데이터베이스를 사용하기가 힘들었습니다.

사실 테스트 컨테이너를 통해 MySQL을 올려 통합테스트를 만들 수도 있는데 로컬 빌드 시에는 이런 통합 테스트가 오래 걸리기도 해서 CI 환경에서만 통합테스트코드가 실행되었으면 좋겠다는 생각이 들었습니다.

통합테스트, 유닛테스트 

간단하게 통합 테스트와 유닛 테스트 코드를 하나씩 만들어보겠습니다.

private val log = KotlinLogging.logger {  }

class IntegrationTest {
    @Test
    @DisplayName("통합테스트")
    fun integration_test() {
        log.info("통합테스트 시작")

        Thread.sleep(5000)

        log.info("통합테스트 종료")
    }
}
private val log = KotlinLogging.logger {  }

class UnitTest {
    @Test
    @DisplayName("유닛테스트")
    fun unit_test() {
        log.info("유닛테스트 시작")
        Thread.sleep(500)
        log.info("유닛테스트 종료")
    }
}

 

먼저 그레이들 빌드스크립트에 test 태스크를 아래와 같이 세팅합니다.

tasks.withType<Test> {
    useJUnitPlatform()

    testLogging {
        events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
    }
}

테스트를 실행해보겠습니다. 캐싱이 되면 출력결과가 안 나올 수 있기 때문에 test 시작하기 전에 clean도 실행시켜 줍니다.

./gradlew clean test

실행결과 통합테스트와 유닛테스트 모두 실행이 되었음을 볼 수 있습니다. 

Filter 사용하기

이제 filter를 통해 통합테스트를 제외시키도록 설정해 보겠습니다. 테스트 태스크를 아래와 같이 수정해 주고 다시 위 커맨드를 실행합니다.

tasks.withType<Test> {
    useJUnitPlatform()

    filter {
        excludeTestsMatching("**.IntegrationTest")
    }

    testLogging {
        events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
    }
}

이번에는 IntegrationTest가 제외된 상태로 실행되었음을 볼 수 있었습니다.

특정 테스트코드를 실행하지 않도록 할 수 있었지만 그렇다면 실행되지 않아야 하는 모든 테스트 코드를 다 적어주기는 힘듭니다. 그래서 테스트 코드를 패키지로 구분하도록 수정해 봅시다.

IntegrationTest를 integrate이라는 패키지를 생성해서 해당 패키지 안으로 이동시키고, UnitTest를 unit이라는 패키지 안으로 이동시킵니다. 그럼 이런 모습이 될 것 같습니다.

그런 다음 태스크를 아래와 같이 수정하면 integrate 패키지 밑에 있는 테스트 코드가 제외가 될 겁니다.

tasks.withType<Test> {
    useJUnitPlatform()

    filter {
        excludeTestsMatching("**.integrate.**")
    }

    testLogging {
        events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
    }
}

주의할 점은 패턴을 위와 같이 설정한 경우 com.example.demo.unit.integrate.UnitTest2 와 같은 코드도 제외 대상이 됩니다. 따라서 좀 더 패턴을 정교하게 만들 필요가 있습니다. 아래와 같이 수정할 수도 있습니다.

tasks.withType<Test> {
    useJUnitPlatform()

    filter {
        excludeTestsMatching("com.example.demo.integrate.**")
    }

    testLogging {
        events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
    }
}

특정 환경에서만 필터 적용하기

빌드스크립트를 위와 같이 수정한 경우 로컬에서는 제외시킬 수 있었지만 CI 환경에서는 실행이 되도록 해야 합니다. 여러 가지 방법이 많을 테지만 저는 예시로 시스템 환경변수를 들겠습니다.

아래와 같이 테스트 태스크를 수정해 보겠습니다.

tasks.withType<Test> {
    useJUnitPlatform()

    if (System.getenv("CI") == null) {
        filter {
            excludeTestsMatching("com.example.demo.integrate.**")
        }
    }

    testLogging {
        events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
    }
}

다음으로 gradle 실행시키기 전에 CI 환경변수를 넣고 시작합니다.

export CI=ci

./gradlew clean test

이제 통합테스트가 실행됨을 알 수 있습니다. 이런 식으로 CI 환경에 변수를 설정해 놓으면 필터가 적용되지 않도록 구성할 수 있습니다.

혹시라도 다시 유닛테스트만 실행하고 싶다면 환경변수를 해제시키고 실행시키면 됩니다.

unset CI

./gradlew clean test

 

반응형

'Programming > Gradle' 카테고리의 다른 글

Gradle Custom Task, Plugin with buildSrc  (0) 2023.03.11
Gradle - 빌드 스크립트 작성 기초  (0) 2022.09.17
Gradle 디렉토리  (0) 2022.09.04
Gradle의 빌드 라이프사이클  (0) 2022.08.28
Gradle에 대해 알아보자.  (0) 2022.08.27