참고
달록의 Jacoco 적용기 (feat. Gradle)
test code를 작성하면 툴에서 test coverage를 확인할 수 있다. 하지만 이는 나만 확인할 수 있고 커버리지 수치가 낮아도 별 상관이 없다. 그냥 내 눈에 보이는 수치일 뿐
하지만 jacoco는 이를 문서화 해주고 커버리지 목표를 설저앟여 일정 수치가 넘어야지만 빌드를 가능하게끔 해주는 기능을 갖고 있다.
더 질 높은 코드를 작성하는 프로젝트를 진행하기 위해 jacoco를 도입해보자.
plugins {
id 'jacoco'
}
// ...
jacoco {
toolVersion = '0.8.8'
}
작성일 기준 가장 최신 버전이 0.0.8이더라 그래서 해당 버전으로 적용했다.
이제 테스트 코드를 실행해보자
테스트 코드가 종료된 뒤 jacoco
폴더가 build 폴더 아래에 생성된걸 확인할 수 있다.
그리고 해당 폴더 아래에는 test.exec 파일이 생성되었는데 이는 우리가 실행해서 읽어볼 수 없다. 해당 파일을 눈으로 볼수 있게 변경해야한다.
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")
}
}
gralde 설정에 다음과 같이 설정을 추가해주고
./gradelw gacocoTestReport
명령어를 실행해주면
파일들이 생성된 것을 확인할 수 있다.
하지만 명령어를 계속해서 쳐서 파일 생성은 귀찮으니 자동으로 생성하도록 수정하자.
tasks.named('test') {
...
finalizedBy 'jacocoTestReport'
}
다음과 같이 수정해주면 test가 종료된 후 자동으로 jacocoTestReport
를 실행한다.
부끄럽지만... ㅜ
jacocoTestCoverageVerification {
violationRules {
rule {
enabled = true
element = 'CLASS'
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.70
}
}
// ...
rule {
// 추가 규칙
}
}
}
enabled
규칙의 활성화 여부를 나타냅니다. 기본 값은 true 입니다.
element
커버리지를 체크할 단위를 설정합니다. 아래와 같은 옵션이 있습니다.
BUNDLE : 패키지 번들 (전체 프로젝트)
CLASS : 클래스
GROUP : 논리적 번들 그룹
METHOD : 메소드
PACKAGE : 패키지
SOURCEFILE : 소스파일
기본값은 BUNDLE 입니다.
counter
코드 커버리지를 측정할 때 사용되는 지표입니다. 아래와 같은 옵션이 있습니다.
LINE : 빈 줄을 제외한 실제 코드의 라인 수
BRANCH : 조건문등의 분기 수
CLASS : 클래스 수
METHOD : 메소드 수
INSTRUCTION : 자바 바이트코드 명령 수
COMPLEXITY : 복잡도
기본값은 INSTRUCTION 입니다.
또한 이전에 설정한 jacocoTestReport
가 실행되어질 때 지표에 대한 값도 체크하도록
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'
}
다음과 같이 gradle을 수정해준다.
jacocoTestReport
에서 보고서에서 제외할 목록을 작성할 수 있다.
jacocoTestReport {
// ...
afterEvaluate {
classDirectories.setFrom(
files(classDirectories.files.collect {
fileTree(dir: it, excludes: [
'**/*Application*',
'**/*Exception*',
'**/*Advice*',
'**/dto/**',
'**/vo/**',
'**/enums/**',
'**/api/**',
'**/config/**',
// ...
])
})
)
}
// ...
}
따로 체크하고 싶지 않은 클래스를 제외시킬 수 있다. 예를들어 Application이나 Dto와 같이 굳이 체크가 필요하지 않다고 생각하는 부분의 클래스들은 제외시키는 기능이다.
jacocoTestCoverageVerification {
violationRules {
rule {
// ...
excludes = [
'*.*Application',
'*.*Exception',
'*.dto.*',
// ...
]
}
}
}
plugins {
...
id 'jacoco'
}
jacoco {
toolVersion = '0.8.8'
}
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")
}
afterEvaluate {
classDirectories.setFrom(
files(classDirectories.files.collect {
fileTree(dir: it, excludes: [
'**/*Application*',
'**/*Exception*',
'**/*Advice*',
'**/dto/**',
'**/vo/**',
'**/enums/**',
'**/api/**',
'**/config/**',
// ...
])
})
)
}
finalizedBy 'jacocoTestCoverageVerification'
}
jacocoTestCoverageVerification {
violationRules {
rule {
enabled = true
element = 'CLASS'
excludes = [
'*.*Application',
'*.*Exception',
'*.*Advice',
'*.dto.*',
'*.vo.*',
'*.enums.*',
'*.api.*',
'*.config.*',
]
limit {
counter = 'METHOD'
value = 'COVEREDRATIO'
minimum = 0.50
}
}
rule {
enabled = true
element = 'CLASS'
excludes = [
'*.*Application',
'*.*Exception',
'*.*Advice',
'*.dto.*',
'*.vo.*',
'*.enums.*',
'*.api.*',
'*.config.*',
]
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.50
}
}
}
}
tasks.named('test') {
outputs.dir snippetsDir
useJUnitPlatform()
finalizedBy 'jacocoTestReport'
}
...
다음과 같이 적용하여 jacoco를 사용해볼 수 있었다.
jacoco를 적용하며 아직 테스트코드를 제대로 작성하지 않아 minimum 기준을 낮춰서 설정해두었는데 저 부분을 꼭 올려야겠다라는 생각이 들었고 지금부터 테스트 기준을 계속해서 맞춰 나가면 더 좋은 코드를 작성할 수 있게될거 같다!