code coverage
코드 커버리지는 테스트 코드가 실제 애플리케이션 코드에서 몇 퍼센트를 실행했는지 분석하는 지표다
단위 테스트/통합 테스트 실행 후 커버리지를 측정하여 테스트가 부족한 부분을 찾아내고 보완하는 데 사용된다
주의점
100% 커버리지가 완벽한 코드 품질을 의미하지 않는다
- 테스트 실행 여부를 평가하지, 테스트의 효과를 측정하지 않는다
- 테스트가 실행되었다고 해서 모든 버그를 발견할 수 없다
mock을 사용한 테스트로 커버리지가 높을 수 있다
- mocking을 사용하면 실제 코드 실행 없이 커버리지가 올라갈 수 있다
로직이 단순한 코드는 커버리지가 낮을 수 있다
- getter/setter 메서드는 테스트하지 않아도 실제 실행에는 문제가 없다
코드 커버리지는 자동화된 지표일 뿐이므로 눈으로 직접 논리적 결함을 확인해야 한다
jacoco
jacoco는 자바 애플리케이션에서 테스트 코드가 실제 코드 블록의 몇 퍼센트를 측정하는 코드 커버리지 분석 도구다
테스트가 충분히 실행되었는지 확인하고 부족한 부분을 보완하여 코드 품질을 향상시키는 데 도움을 준다
주요 특징
바이트코드 기반 동작: 바이트코드를 변형하여 코드 실행 여부를 추적한다
빠른 실행 속도: 런타임 오버헤드가 낮아서 빌드/테스트 속도에 미치는 영향이 적다
테스트 프레임워크와의 통합: junit, testng 등 자바 기반 테스트 프레임워크와 호환된다
ci/cd 연동: maven, gradle, sonarqube 등과 연동하여 코드 품질을 관리할 수 있다
보고서 제공: html, xml, csv 형태의 커버리지 보고서를 생성한다
코드 커버리지 측정 기준
라인 커버리지
소스 코드의 각 라인이 최소 한 번 실행되었는지 측정한다
계산 방식: 테스트 코드로 실행된 라인 수 / 전체 코드 라인 수 * 100%
public void example(boolean flag) {
System.out.println("hello"); // 1
if (flag) { // 2
System.out.println("test"); // 3
}
}
테스트 코드가 1만 실행하고 2,3을 건너뛰면 라인 커버리지는 33.3%가 된다
브랜치 커버리지
if, switch, for, while 등 조건문이 모든 경우를 거쳤는지 측정한다
계산 방식: 실행된 분기 수 / 전체 분기 수 * 100%
public void checkNumber(int x) {
if (x > 0) { // 분기 1 x > 0
System.out.println("positive");
} else { // 분기 2 x <= 0
System.out.println("non-positive");
}
}
checkNumber(5)
테스트 시 x > 0 분기만 실행되므로 브랜치 커버리지 50%로 측정된다
checkNumber(0)
테스트 시 x <= 0 분기까지 실행되므로 브랜치 커버리지 100%로 측정된다
메서드 커버리지
클래스 내의 모든 메서드가 최소 한 번 실행되었는지 측정한다
계산 방식: 테스트된 메서드의 수 / 전체 메서드 수 * 100%
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
}
add 메서드 테스트 시 메서드 커버리지 50%
add, subtract 메서드 테스트 시 메서드 커버리지 100%
클래스 커버리지
특정 클래스가 한 번이라도 테스트에서 실행되었는지 측정한다
계산 방식: 테스트된 클래스 수 / 전체 클래스 수 * 100%