본문 바로가기
빌드노트 검색

빌드노트

-DskipTests를 줘도 Maven 테스트 컴파일이 실패하는 이유

Maven의 -DskipTests는 테스트 실행을 생략해도 테스트 소스 컴파일은 남긴다. 고정 버전 프로젝트에서 컴파일 오류와 단언 실패를 비교하고, 실패 목표가 testCompile인지 surefire:test인지에 따라 테스트 수정과 제한적 컴파일 생략을 판단한다.

Maven의 package에 -DskipTests를 붙여도 src/test/java의 컴파일 오류로 빌드가 멈출 수 있다. Surefire의 skipTests는 테스트 실행을 생략하지만, 그 앞의 테스트 소스 컴파일은 남긴다. 실패 로그가 maven-compiler-plugin:…:testCompile을 가리킨다면 먼저 해당 테스트 소스의 오류를 확인해야 한다.

테스트 코드를 고치는 것이 기본 선택이다. 당장 테스트 검증 없이 패키지만 만들어야 하는 제한된 작업이라면 -Dmaven.test.skip=true로 컴파일까지 생략할 수 있다. 이때 만들어진 JAR은 깨진 테스트를 고쳤다는 증거가 아니다.

컴파일과 실행은 다른 단계다

일반적인 jar 프로젝트에서 Maven은 test-compile 단계의 compiler:testCompile로 테스트 소스를 컴파일하고, 그 뒤 test 단계의 surefire:test로 테스트를 실행한다. package를 요청하면 이 앞 단계들도 순서대로 거친다. 단계 이름 test-compile과 로그에 찍히는 목표 이름 testCompile은 표기가 다르다. Maven 빌드 생명주기 문서 (새 탭에서 열림)

skipTests와 maven.test.skip은 이 중 어디까지 생략하는지가 다르다. Surefire 3.5.4는 skipTests를 실행 생략 옵션으로 설명하고, Compiler Plugin 3.14.1은 maven.test.skip을 테스트 소스 컴파일 생략 속성으로 받는다. Surefire의 skipTests 설명 (새 탭에서 열림), Compiler의 skip 설명 (새 탭에서 열림)

그래서 오류를 볼 때는 마지막 BUILD FAILURE보다 Failed to execute goal에 나온 플러그인과 목표가 더 유용하다. compiler:…:testCompile이면 테스트 소스를 실행 가능한 클래스로 만드는 중이고, surefire:…:test이면 테스트 실행을 담당하는 목표에서 실패한 것이다. 후자는 단언 실패 외에 테스트 실행기 초기화 오류도 가능하므로 바로 앞 원인까지 읽는다.

존재하지 않는 메서드를 테스트에서 호출했다

별도 교육용 프로젝트를 만들어 세 경우를 비교했다. Windows 11, Maven 3.9.16, OpenJDK 17.0.2에서 Compiler 3.14.1, Surefire 3.5.4, JUnit 4.13.2를 고정했다. main 코드는 항상 같은 두 정수를 더한다.

public static int sum(int a, int b) {
    return a + b;
}

정상 테스트의 assertEquals(4, Calculator.sum(2, 2));는 기본 clean package에서 테스트 1개를 통과하고 JAR을 만들었다. 다음에는 테스트의 호출만 아래처럼 바꿨다. missingSum은 main 코드에 없는 메서드다.

assertEquals(4, Calculator.missingSum(2, 2));

이 소스는 기본 빌드와 -DskipTests=true 빌드에서 모두 종료 코드 1로 실패했다. 두 경우 main 클래스는 만들어졌지만 테스트 클래스와 JAR은 없었다. -DskipTests=true 실행 로그에서 단계와 오류 원인을 발췌하면 다음과 같다.

[INFO] --- compiler:3.14.1:testCompile (default-testCompile) @ skip-test-lab ---
  symbol:   method missingSum(int,int)
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.14.1:testCompile (default-testCompile) on project skip-test-lab: Compilation failure

이 실행에서는 surefire:test에 도달하지 않았다. 테스트를 실행하지 않기로 했어도 테스트 소스를 컴파일하는 중에 먼저 멈춘 것이다.

같은 오류 소스에 -Dmaven.test.skip=true를 주자 종료 코드 0으로 JAR이 만들어졌다. 로그에는 Not compiling test sources와 Tests are skipped.가 나왔고 테스트 클래스는 없었다. main 컴파일은 그대로 수행됐다. Surefire의 테스트 생략 예제 (새 탭에서 열림)도 두 속성의 이 차이를 설명한다.

단언이 틀린 테스트에서는 결과가 달랐다

이번에는 없는 메서드 호출을 없애고, 정상 메서드에 틀린 기대값만 넣었다. 2 + 2의 결과를 5라고 요구한 것이다.

assertEquals(5, Calculator.sum(2, 2));

기본 빌드는 테스트 클래스를 만든 뒤 Surefire에서 실패했다. 발췌한 출력에도 컴파일 오류와 다른 목표가 남았다.

java.lang.AssertionError: expected:<5> but was:<4>
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.5.4:test (default-test) on project skip-test-lab: There are test failures.

옵션별 관찰을 모으면 다음과 같다. 종료 코드 0은 이 실험에서 패키징까지 성공했다는 뜻이다.

  • 컴파일이 깨진 테스트: 기본 실행은 1, -DskipTests=true도 1, -Dmaven.test.skip=true는 0이었다.
  • 단언만 틀린 테스트: 기본 실행은 1, -DskipTests=true와 -Dmaven.test.skip=true는 모두 0이었다. 다만 skipTests에서는 테스트 클래스가 생겼고 maven.test.skip에서는 생기지 않았다.

테스트 소스의 컴파일 검사는 유지하면서 실행만 생략하려는 목적에는 skipTests가 맞는다. 자기 로그가 Surefire의 단언 실패라면 기대값과 구현 중 어느 쪽이 요구사항과 다른지도 확인한다.

각 비교는 새 프로젝트 폴더에서 clean package로 실행했다. 이전 테스트 클래스나 JAR이 남아 성공처럼 보이는 경우를 피하기 위해서다. 만들어진 네 JAR의 main을 실행하면 모두 sum=4를 출력했다. 정상 main을 패키징할 수 있다는 관찰이며, 생략한 테스트가 통과했다는 뜻은 아니다.

내 빌드에서는 실패 목표부터 고른다

이미 실패 로그가 있다면 Failed to execute goal 줄과 그 위의 첫 오류부터 확인한다. 직접 다시 확인하려면 JDK와 Maven이 설치된 개발용 사본에서 pom.xml이 있는 폴더로 이동한다. 아래는 Windows PowerShell 명령이다. clean은 기존 빌드 산출물을 지우며, 패키징 과정에서는 그 프로젝트에 연결된 플러그인들도 실행된다.

mvn.cmd -B "-DskipTests=true" clean package
$LASTEXITCODE

실험의 없는 메서드 호출에서는 testCompile 오류와 종료 코드 1이 나왔다. 자기 로그도 같다면 오류에 나온 테스트 파일과 행을 열어, 삭제·변경된 메서드 호출이나 잘못된 import 등을 고친다. 반대로 compiler:…:compile에서 실패했다면 main 소스 컴파일 문제이므로 여기서 비교한 테스트 생략 범위에 해당하지 않는다. 의존성 다운로드나 다른 플러그인에서 실패했을 때도 그 원인을 별도로 확인한다.

테스트 소스가 아직 컴파일되지 않아도 되는 임시 산출물 확인에 한해서는 다음 명령을 선택할 수 있다. -D 속성 전체를 따옴표로 감싸 PowerShell에 전달한다.

mvn.cmd -B "-Dmaven.test.skip=true" clean package
$LASTEXITCODE

실험에서는 종료 코드 0과 Not compiling test sources, Tests are skipped.를 확인했다. 이 결과는 테스트 컴파일과 실행을 생략한 상태다. 테스트 오류를 수정한 뒤에는 두 생략 옵션 없이 다시 실행한다.

mvn.cmd -B clean package
$LASTEXITCODE

이 실험에서 테스트 호출을 sum, 기대값을 4로 둔 정상 입력은 종료 코드 0과 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0을 남겼다. 자기 프로젝트에서는 실제로 실행된 테스트 수와 결과도 함께 확인한다.

위 비교는 고정한 Compiler·Surefire를 쓰는 단일 모듈 JAR 프로젝트의 package 범위다. Failsafe 통합 테스트, 별도 코드 생성, 사용자 정의 플러그인은 실행하지 않았다. 이 속성을 모든 Maven 작업을 끄는 전역 스위치로 해석하면 안 된다. 결과가 다르면 로그에 나온 플러그인 버전과 해당 모듈의 POM·활성 프로필에서 생략 설정을 확인한다.

← 전체 글 보기