Gradle 로 테스트 후 빌드 하기
느린 테스트는 빼고 테스트 후 빌드 하기
아무튼 우리는 테스트를 해야한다. 그리고 빌드 시에 테스트도 함께 수행하도록 하면 나의 작업이 regression 되지 않았는지 주의하며 진행할 수 있다. 다만, 빌드 시 느린 테스트는 빼고 빌드를 하게 만들고 싶었다.
그러나 IntelliJ 에서 다소 사소한 문제를 만나게 되는데…
배경
시간이 오래 걸리는 Slow Test 를 그냥 수행하고 빌드하는 방법도 있을 수 있다. 그러나 Integration Test 같은 경우에는 빌드 환경에서는 동작하지 않을 수도 있고, 불필요하게 많은 설정을 요구할 수도 있다. 꼭 느리지 않더라도 로컬 개발에서만 테스트해보고 빌드 파이프라인에서는 무시하고 싶은 테스트가 있을 수도 있다.
기본적인 방법
Gradle 에서는 테스트를 어떻게 수행할 지 정의할 수 있다. 여기에서 특정 테스트를 제외하는 방법은 이미 많이 공유되고 있으니 쉽게 찾을 수 있다.
Tag, Cateogry 를 이용해 특정 테스트를 포함/비포함
JUnit 5 부터는 @Tag 또는 @Category 라는 annotation 을 지원하여 테스트를 태깅할 수 있으며, 이를 이용해 테스트에 포함하거나 제외 할 수 있다.
https://www.baeldung.com/junit-5-gradle#configuring-junit-5-tests-with-gradle
test {
useJUnitPlatform {
includeTags 'fast'
excludeTags 'slow'
}
}
Package 나 파일명 wildcard 를 이용하여 포함/비포함
뿐만 아니라 Gradle 에서는 filter 를 통해 특정 패키지에 포함된 테스트나, 특정 이름의 테스트 클래스만 수행되게 할 수 있다.
https://docs.gradle.org/current/userguide/java_testing.html#test_filtering
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"
}
}
Gradle 명령시 특정 테스트 포함/비포함 옵션 전달
만약 gradle 빌드 명령을 지정할 수 있다면, —tests command 를 통해 특정 테스트를 지정할 수 있다.
https://stackoverflow.com/questions/22505533/how-to-run-only-one-unit-test-class-using-gradle
$ gradle test --tests org.gradle.SomeTest.someSpecificFeature
$ gradle test --tests '*SomeTest.someSpecificFeature'
$ gradle test --tests '*SomeSpecificTest'
기본적인 방법의 문제점
보통은 위 방법들을 사용하는 것 만으로도 충분하다.
주의: 개발자 환경마다 다를 수 있음
하지만 문제가 되는 지점은 우리가 IntelliJ 등 IDE 를 통해 테스트를 수행할 때 발생한다. Gradle 프로젝트는 기본적으로 테스트를 gradle 의 task 로 실행하게 되는데, 이때 gradle 설정을 참조하게 된다.
만약 위 방법들을 통해서 테스트를 gradle 설정에서 제외시키면, 제외된 테스트는 (당연하게도) gradle 의 task 로 실행할 수 없게된다. 제외된 테스트를 직접 특정하여 시도해보면 테스트가 존재 하지 않는다고 표시된다.
No tests found for given includes: [com.mys.project.YourSlowTest](--tests filter)
물론 직접 gradle 명령을 통한 방법이나, JUnit 으로 테스트를 수행할 때에는 gradle 설정에서 제외 되었더라도 문제 없이 실행된다. 본문은 gradle 을 이용한 테스트에 대해 한정한다.
기본적으로는 제외하되 직접 실행은 되게 하기
IDE 에서 gradle 을 통해 실행되는 테스트는 gradle 설정의 포함/비포함의 영향을 받게 된다. 그래서 제외된 테스트는 gradle 로는 더 이상 실행할 수 없게 되었다.
그렇지만 별도로 특정해서 테스트를 수행하고 싶을 때는 제외되지 않게 하고 싶다면?
방법
일단 이런 문제가 다른 사람들에게는 큰 문제가 아닌듯 잘 검색되지 않는다.
오랜시간 검색 끝에 다음의 질문과 답변이 큰 힌트가 되었다.
https://stackoverflow.com/questions/71828925/how-to-run-a-single-test-that-is-excluded
commandLineIncludePatterns 이 존재하지 않으면 제외시켜라
IDE 에서 gradle 로 특정 테스트를 실행하면 IDE 는 자동으로 다음과 같은 명령어를 만들어 실행 시킨다.
$ gradle :module:test --tests "com.mys.project.YourSlowTest"
특정한 테스트만 실행시키기 위해 —tests 이후에 내가 특정한 테스트 “com.mys.project.YourSlowTest” 가 command 로 전달이 되는데, 이 부분이 바로 commandLineIncludePatterns
이다.
반면 빌드를 했을 때 수행되는 테스트에서는 —tests 를 전달하지 않는다.
참고로 아래는 Gradle 팀의 commandLineIncludePatterns
에 대한 내용.
https://discuss.gradle.org/t/get-tests-specified-by-tests-commandline-argument/40324/9
해결
빌드 시에는 느린 테스트를 제외시킨다. 느린 테스트에는 tag 를 붙여둔다. 단, 느린 테스트를 단독 수행시에는 테스트에서 제외 시키지 않는다.
commandLineIncludePatterns 에 대한 조건은 doFirst 로 정의해야 한다. 그래야 테스트가 시작되기 전에 excludeTags 가 적용될 수 있기 때문이다.
test {
useJUnitPlatform()
doFirst {
// build 시에는 slow-test 를 제외하고 test 를 수행한다.
// 그러나 개별 test 수행 시에는 slow-test 도 수행할 수 있게 한다.
if (filter.commandLineIncludePatterns.empty) {
useJUnitPlatform {
excludeTags "slow-test"
}
}
}
}
결론
IntelliJ 환경에서 Gradle 프로젝트의 특정 테스트만 잘(?) 제외시킬 방법에 대해 찾아보았다.
많은 개발자에게 도움이 될만한 내용은 아니지만, 비슷한 문제를 해결하는데 도움이 되길 바라며…