코드 커버리지란 소프트웨어 테스트의 측정 항목 중 하나로, 테스트를 수행했을 때 얼마나 많은 코드가 실행되었는지를 나타내는 지표입니다. 즉, 소스 코드 중에서 얼마나 많은 부분이 테스트 케이스에 의해 실행되었는지를 백분율로 나타내는 것입니다.
JaCoCo
Cobertura
Emma
build.gradle
id ‘jacoco’
를 추가해준다plugins {
id 'java'
id 'org.springframework.boot' version '2.7.9'
id 'io.spring.dependency-management' version '1.1.0'
id 'jacoco'
}
jacocoTestReport {
//레포트 파일 생성
reports {
html.enabled true
xml.enabled false
csv.enabled true
}
// jacocoReport 에서 q 클래스는 제외
def Qdomains = []
for(qPattern in "**/QA" .. "**/QZ"){
Qdomains.add(qPattern+"*")
}
afterEvaluate {
// 레포트에서 제외 항목 추가
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it,
exclude: ["**/*Application*",
"**/_global/*",
"**/dto/*",
"**/redis/*"
] + Qdomains)
}))
}
finalizedBy 'jacocoTestCoverageVerification'
}
violationRules
메서드는 커버리지 통과 기준을 설정 한다.jacocoTestCoverageVerification {
def Qdomains = []
for (qPattern in "*.QA".."*.QZ") { // qPattern = "*.QA","*.QB","*.QC", ... "*.QZ"
Qdomains.add(qPattern + "*")
}
violationRules {
rule {
enabled = true
element = 'CLASS'
// includes = []
limit {
counter = 'BRANCH'
value = 'COVEREDRATIO'
minimum = 0.90
}
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.80
}
limit {
counter = 'LINE'
value = 'TOTALCOUNT'
maximum = 200
}
excludes = [ "**/*Application*",
"**/_global/*",
"**/dto/*",
"**/redis/*"
] + Qdomains
}
}
}
enabled
true
elements
ICoverageNode.ElementType (JaCoCo 0.8.10.202304030907 API)
BUNDLE
: 묶음 커버리지(Bundle Coverage)를 나타냅니다. 이는 프로젝트의 모든 바이트코드 중 얼마나 많이 커버리지가 측정되었는지를 나타냅니다. 이 요소는 대개 프로젝트의 전체적인 커버리지를 확인하기 위해 사용됩니다.CLASS
: 클래스 커버리지(Class Coverage)를 나타냅니다. 이는 프로젝트의 모든 클래스 중 몇 개의 클래스가 테스트되었는지를 나타냅니다.GROUP
: 그룹 커버리지(Group Coverage)를 나타냅니다. 이는 프로젝트의 패키지 구조를 기반으로 각 패키지에 대한 커버리지를 나타냅니다.METHOD
: 메서드 커버리지(Method Coverage)를 나타냅니다. 이는 프로젝트의 모든 메서드 중 몇 개의 메서드가 테스트되었는지를 나타냅니다.PACKAGE
: 패키지 커버리지(Package Coverage)를 나타냅니다. 이는 프로젝트의 모든 패키지 중 몇 개의 패키지가 테스트되었는지를 나타냅니다.SOURCEFILE
: 소스 파일 커버리지(Source File Coverage)를 나타냅니다. 이는 프로젝트의 모든 소스 파일 중 몇 개의 파일이 테스트되었는지를 나타냅니다.includes
ICoverageNode.CounterEntity (JaCoCo 0.8.10.202304030907 API)
**는 **
service`**counter
ICoverageNode.CounterEntity (JaCoCo 0.8.10.202304030907 API)
BRANCH
: 분기 커버리지(Branch Coverage)를 나타냅니다. 이는 코드에서 조건문, switch 문 등의 브랜치(가지)가 얼마나 많이 실행되었는지를 나타냅니다. 즉, 브랜치가 있는 조건문에서 모든 경우의 수를 실행해보았는지 여부를 확인하는 지표입니다.CLASS
: 클래스 커버리지(Class Coverage)를 나타냅니다. 이는 프로젝트의 모든 클래스 중 몇 개의 클래스가 테스트되었는지를 나타냅니다.COMPLEXITY
: 코드 복잡성(Complexity)을 나타냅니다. 이는 코드 내의 제어 흐름(예: if문, loop문 등)이 얼마나 복잡한지를 나타내는 지표입니다.INSTRUCTION
: 명령어 수(Instruction Coverage)를 나타냅니다. 이는 코드의 모든 명령어 중 몇 개가 실행되었는지를 나타냅니다.LINE
: 라인 커버리지(Line Coverage)를 나타냅니다. 이는 코드에서 얼마나 많은 라인이 테스트되었는지를 나타냅니다.METHOD
: 메서드 커버리지(Method Coverage)를 나타냅니다. 이는 프로젝트의 모든 메서드 중 몇 개의 메서드가 테스트되었는지를 나타냅니다.value
ICounter.CounterValue (JaCoCo 0.8.10.202304030907 API)
COVEREDCOUNT
: 커버된 항목의 수를 나타냅니다. 예를 들어, COVEREDCOUNT
가 10인 경우, 해당 항목에 대해 10개의 코드 라인이 테스트를 통과했다는 것을 의미합니다.COVEREDRATIO
: 커버된 항목의 비율을 나타냅니다. 예를 들어, COVEREDRATIO
가 80%인 경우, 해당 항목의 코드 라인 중 80%가 테스트를 통과했다는 것을 의미합니다.MISSEDCOUNT
: 커버되지 않은 항목의 수를 나타냅니다. 예를 들어, MISSEDCOUNT
가 5인 경우, 해당 항목에 대해 5개의 코드 라인이 테스트를 통과하지 못했다는 것을 의미합니다.MISSEDRATIO
: 커버되지 않은 항목의 비율을 나타냅니다. 예를 들어, MISSEDRATIO
가 20%인 경우, 해당 항목의 코드 라인 중 20%가 테스트를 통과하지 못했다는 것을 의미합니다.TOTALCOUNT
: 전체 항목의 수를 나타냅니다. 예를 들어, TOTALCOUNT
가 20인 경우, 해당 항목에 대해 총 20개의 코드 라인이 존재한다는 것을 의미합니다.minimum
exclude
**는 이름이 **
Test`**로 끝나는 모든 클래스를 검증 대상에서 제외합니다. 이렇게 하면 테스트 코드나 mock 클래스 같이 실제로 실행되지 않는 코드를 코드 커버리지 검증에서 제외할 수 있습니다.@ExtendWith(MockitoExtension.class)
@DisplayName("유저 테스트")
class UserServiceTest {
@InjectMocks
private UserService userService;
@Mock
private UserRepository userRepository;
@Mock
private PasswordEncoder passwordEncoder;
@Test
@DisplayName("로그인-성공")
void loginTest() {
LoginRequestDto loginRequestDto = LoginRequestDto.of("test1", "123123");
HttpServletResponse responseMock = mock(HttpServletResponse.class);
User user = User.of("test1", "1234");
when(userRepository.findByUserId(any())).thenReturn(Optional.of(user));
when(passwordEncoder.matches(any(), any())).thenReturn(true);
userService.login(loginRequestDto, responseMock);
}
@Test
@DisplayName("로그인-아이디-실패")
void loginFailIdTest() {
LoginRequestDto loginRequestDto = LoginRequestDto.of("test1", "123123");
HttpServletResponse responseMock = mock(HttpServletResponse.class);
when(userRepository.findByUserId(any())).thenReturn(Optional.empty());
Exception exception = assertThrows(CustomException.class, () ->
userService.login(loginRequestDto, responseMock)
);
assertEquals(exception.getMessage(), ErrorType.NOT_MATCHING_INFO.getMsg());
}
@Test
@DisplayName("로그인-패스워드-실패")
void loginFailPwTest() {
LoginRequestDto loginRequestDto = LoginRequestDto.of("test1", "123123");
HttpServletResponse responseMock = mock(HttpServletResponse.class);
User user = User.of("test1", passwordEncoder.encode("5678"));
when(userRepository.findByUserId(any())).thenReturn(Optional.of(user));
Exception exception = assertThrows(CustomException.class, () -> {
userService.login(loginRequestDto, responseMock);
});
assertEquals(exception.getMessage(), ErrorType.NOT_MATCHING_INFO.getMsg());
}
}
경로\build\reports\jacoco\test\html\index.html에서 테스트 커버리지를 확인 가능하다.
붉은색으로 표기된 항목은 테스트를 작성하지 않은 코드이고
초록색은 테스트를 작성한 코드로
아래 사진 처럼 확인이 가능하다!