Jacoco는 테스트 커버리지를 개발자가 직접 확인하지 않고 자동으로 확인해주는 도구이다. 라인, 브랜치 커버리지를 제공해주며 개발자가 지정한 커버리지에 도달하지 못하며 빌드를 실패하도록 설정도 가능하다.
다른 자바 진영 테스트 커버리지 라이브러리도 있지만 내가 Jacoco를 선택한 가장 큰 이유는 다른 라이브러리는 레퍼런스가 별로 없고, Jacoco가 설정이 비교적 쉽고 간단하여 선택하였다.
jacoco {
// jacoco 버전
toolVersion = '0.8.7'
// 테스트 결과 저장하는 곳 경로 지정
// 기본값은 "$/jacoco"
// reportsDir = file("$buildDir/customJacocoReportDir"
}
plugins {
id 'jacoco'
}
Gradle 설정에 위의 코드를 넣어 버전과 테스트 커버리지 결과를 저장할 곳을 지정해준다. 기본은 build 파일 아래의 jacoco 폴더가 생성되도록 되어있다.
test {
useJUnitPlatform()
finalizedBy 'jacocoTestReport'
jacoco {
excludes += ["com/capstone/wanf/error",
"com/capstone/wanf/config/**",
"com/capstone/wanf/common/**",
"com/capstone/wanf/**/dto/**",
"com/capstone/wanf/auth/**"]
}
}
위는 gradle test 테스크 코드이다. finalizedBy는 이 테스크가 실행되고 종료되어야 한다는 명령어이다. 즉, jacocoTestReport가 실행되고 종료되어야 한다는 의미이다. jacoco {...} 블록은 테스트 보고서에서 제외할 클래스를 설정한다.
jacocoTestReport {
reports {
xml.enabled true
csv.enabled true
html.enabled true
xml.destination file("${buildDir}/jacoco/index.xml")
csv.destination file("${buildDir}/jacoco/index.csv")
html.destination file("${buildDir}/jacoco/index.html")
}
finalizedBy 'jacocoTestCoverageVerification'
def Qdomains = []
for(qPattern in "**/QA" .. "**/QZ"){
Qdomains.add(qPattern+"*")
}
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it,
exclude: ["com/capstone/wanf/error",
"com/capstone/wanf/config/**",
"com/capstone/wanf/common/**",
"com/capstone/wanf/**/dto/**"]+ Qdomains)
}))
}
}
jacocoTestReport는 jacoco의 테스트 커버리지 결과 지표를 html이나 xml파일로 보여줄 수 있는 테스크이다. reports {...} 블록은 html, xml, csv파일을 저장할 것인지, 어디에 저장할 것인지를 지정해주었다. 그리고 QueryDSL를 사용하면 생기는 Qdomain을 테스트 결과에 포함시키지 않도록 배열에 저장해준었다. 그 후 afterEvaluate 블록에서 테스트 파일에 포함시키지 않을 패키지와 도메인을 설정해 주었다.
jacocoTestCoverageVerification {
violationRules {
rule {
// 각 클래스
element = 'CLASS'
// 분기문 커버리지
limit {
counter = 'BRANCH'
value = 'COVEREDRATIO'
minimum = 0
}
// 라인 커버리지
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.0
}
// 코드에서 사용하는 메소드 중, 테스트가 실행된 메소드의 비율
limit {
counter = 'METHOD'
value = 'COVEREDRATIO'
minimum = 0
}
excludes = [
'**/*Application*',
'**/*dto*',
'**/*Response*',
'**/*config*',
'**/*ErrorCode*',
"*Q*", // querydsl
]
}
rule {
element = 'METHOD'
// 최대 method 라인 수
limit {
counter = 'LINE'
value = 'TOTALCOUNT'
maximum = 200
}
}
}
}
jacocoTestCoverageVerification 테스크는 테스트 룰을 지정하는 테스크이다. violationRules 안에는 rule {...} 블록이 있는데 rule은 jacoco test 규칙을 정해준다. rule 안의 규칙을 보면 element와 linit가 있다. element는 규칙이 적용되는 대상을 지정해주는데 CLASS, LINE, Methode 이렇게 지정해줄 수 있다. limit는 지정된 적용 범위 카운터에 대한 한계 및 임계값을 정의합니다. 위에서 보면 counter에 LiNE이 되어 있으면 LINE 커버리지를 측정하게 된다. mininum은 임계치를 의미하며 이를 도달하지 못하면 빌드가 실패하게 된다.
test 테스크 진행 후 지정해준 경로에 html 파일이 생겼을 것이다. 이를 열어보면 위의 이미지처럼 렌더링되게 된다. 이렇게 현재 얼마나 테스트가 작성되어 있는지 알 수 있다.
Jacoco를 이용해서 테스트 커버리지를 측정해보니 어떤 부분이 테스트가 적용되고 적용되지 않았는지를 알 수 있고 내가 의도하지 않은 부분에 테스트가 적용되면서 코드의 효율성 또한 고려하게 되었다. 처음에는 커버리지를 왜 측정하는지도 의문이 갔지만 해보니깐 버그도 많이 찾게 되고 품질도 향상되었다. 나중에 CI 파이프라인에 Jacoco 스텝도 넣으면 좋을 것 같다.