1. JacoCoCo란?
JaCoCo는 자바 코드 커버리지를 체크하는데 사용하는 오픈소스 라이브러리이다.
- Line, Branch Coverage 제공
- 코드 커버리지 결과를 파일 형태로 저장 가능
- html, xml, csv
- 설정한 커버리지 기준을 만족하는지 확인 가능
2. 스프링 부트 JaCoCo 적용
2.1 JaCoCo 플러그인 추가
Gradle 설정에 JaCoCo 플러그인을 추가하고 플러그인 설정을 한다. reportsDir로 테스트 결과 리포트를 저장할 경로를 바꿀 수 있다.
build.gradle
plugins {
id 'jacoco'
}
jacoco {
// JaCoCo 버전
toolVersion = "0.8.5"
// 테스트결과 리포트를 저장할 경로 변경
// default는 "${project.reporting.baseDir}/jacoco"
// reportsDir = file("$buildDir/customJacocoReportDir")
}
만약 프로젝트를 코틀린으로 하고 있다면 다음과 같이 입력한다.
build.gradle.kts
plugins {
jacoco
}
jacoco {
// JaCoCo 버전
toolVersion = "0.8.5"
// 테스트결과 리포트를 저장할 경로 변경
// default는 "${project.reporting.baseDir}/jacoco"
// reportsDir = file("$buildDir/customJacocoReportDir")
}
추가를 완료하였으면 Reload All Gradle Projects 버튼을 클릭한다.
2.2 Gradle task 설정 - 테스트 리포트 저장과 커버리지 체크
Jacoco Gradle 플러그인에는 2가지 task가 있다.
- jacocoTestReport : 바이너리 커버리지 결과를 사람이 읽기 좋은 형태의 리포트로 저장한다. SonarQube 등으로 연동하기 위해 xml, csv같은 형태로도 리포트를 생성할 수 있다.
- jacocoTestCoverageVerification: 내가 원하는 커버리지 기준을 만족하는지 확인해주는 task이다.
build.gradle
jacocoTestReport {
reports {
// 원하는 리포트를 켜고 끌 수 있습니다.
html.required.set(true)
xml.required.set(false)
csv.required.set(false)
// 각 리포트 타입 마다 리포트 저장 경로를 설정할 수 있습니다.
// html.destination file("$buildDir/jacocoHtml")
// xml.destination file("$buildDir/jacoco.xml")
}
}
jacocoTestCoverageVerification {
violationRules {
rule {
element = 'CLASS'
limit {
counter = 'BRANCH'
value = 'COVEREDRATIO'
minimum = 0.90
}
excludes = []
}
}
}
build.gradle.kts
tasks.jacocoTestReport {
reports {
// 원하는 리포트를 켜고 끌 수 있습니다.
html.required.set(true)
xml.required.set(false)
csv.required.set(false)
// 각 리포트 타입 마다 리포트 저장 경로를 설정할 수 있습니다.
// html.destination = file("$buildDir/jacocoHtml")
// xml.destination = file("$buildDir/jacoco.xml")
}
}
tasks.jacocoTestCoverageVerification {
violationRules {
rule {
element = "CLASS"
limit {
counter = "BRANCH"
value = "COVEREDRATIO"
minimum = "0.90".toBigDecimal()
}
excludes = listOf(
// "*.test.*",
"*.Kotlin*"
)
}
}
}
element
커버리지를 체크할 기준(단위)을 정할 수 있으며, 총 6개의 기준이 존재
- BUNDLE : 패키지 번들(프로젝트 모든 파일을 합친 것. default)
- CLASS : 클래스
- GROUP : 논리적 번들 그룹
- METHOD : 메서드
- PACKAGE : 패키지
- SOURCEFILE : 소스 파일
counter
limit 메서드를 통해 지정할 수 있으며 커버리지 측정의 최소 단위. 이때 측정은 java byte code가 실행된 것을 기준으로 측정되고, 총 6개의 단위가 존재한다.
- BRANCH : 조건문 등의 분기 수
- CLASS : 클래스 수, 내부 메서드가 한 번이라도 실행된다면 실행된 것으로 간주한다.
- COMPLEXITY : 복잡도
- INSTRUCTION : Java 바이트코드 명령 수 (default)
- METHOD : 메서드 수, 메서드가 한 번이라도 실행된다면 실행된 것으로 간주한다.
- LINE : 빈 줄을 제외한 실제 코드의 라인 수, 라인이 한 번이라도 실행되면 실행된 것으로 간주한다.
value
value는 limit 메서드를 통해 지정할 수 있으며 측정한 커버리지를 어떠한 방식으로 보여줄 것인지를 말한다. 총 5개의 방식이 존재한다.
- COVEREDCOUNT : 커버된 개수
- COVEREDRATIO : 커버된 비율, 0부터 1사이의 숫자로 1이 100%이다. (default)
- MISSEDCOUNT : 커버되지 않은 개수
- MISSEDRATIO : 커버되지 않은 비율, 0부터 1사이의 숫자로 1이 100%이다.
- TOTALCOUNT : 전체 개수
minimum
minimum은 counter 값을 value에 맞게 표현했을 때 최솟값을 말한다. 이 값을 통해 jacocoTestCoverageVerification의 성공여부가 결정된다.
해당 값은 BigDecimal 타입이고 표기한 자릿수만큼 value가 출력됩니다. 만약 커버리지를 80%를 원했는데 0.80이 아니라 0.8을 입력하면 커버리지가 0.87이라도 0.8로 표시된다.
excludes
커버리지를 측정할 때 제외할 클래스를 지정할 수 있다. 패키지 레밸의 경로로 지정하여야하고 경로에는 * 와 ? 를 사용할 수 있다.
2.3 test Task 설정
JaCoCo 플러그인은 모든 test 타입의 Task에 JacocoTaskExtension을 추가하고 test Task에 그 설정을 변경할 수 있게한다.
아래는 default 설정이다. 각 설정값은 오버라이드가 가능하다.
build.gradle
test {
jacoco {
enabled = true
destinationFile = file("$buildDir/jacoco/${name}.exec")
includes = []
excludes = []
excludeClassLoaders = []
includeNoLocationClasses = false
sessionId = "<auto-generated value>"
dumpOnExit = true
classDumpDir = null
output = JacocoTaskExtension.Output.FILE
address = "localhost"
port = 6300
jmx = false
}
}
build.gradle.kts
tasks.getByName<Test>("test") {
extensions.configure(JacocoTaskExtension::class) {
isEnabled = true
destinationFile = file("$buildDir/jacoco/$name.exec")
includes = listOf()
excludes = listOf()
excludeClassLoaders = listOf()
isIncludeNoLocationClasses = false
sessionId = "<auto-generated value>"
isDumpOnExit = true
classDumpDir = null
output = JacocoTaskExtension.Output.FILE
address = "localhost"
port = 6300
isJmx = false
}
}
2.4 JaCoCo 플러그인 Task 실행 순서
JaCoCo 플러그인을 통해서 jacocoTestReport Task로 리포트를 생성하기 이전에 test Task가 실행되어야하고, jacocoTestRport Task에는 test Task와의 의존성이 설정되어있지 않다.
위의 의존성 설정은 test Task의 설정에 한 줄만 추가하면 해결할 수 있다.
한가지 설정을 더 해야하는데 jacocoTestReport Task와 jacocoTestCoverageVerification Task간의 순서도 중요하다.
요약하면 test -> jacocoTestReport -> jacocoTestCoverageVerification 순서로 task를 실행해야한다.
이 순서는 finalizedBy라는 메서드를 사용하여 설정할 수 있다.
build.gradle
test {
useJUnitPlatform()
finalizedBy 'jacocoTestReport' // 추가
}
jacocoTestReport {
reports {
html.enabled true
csv.enabled true
xml.enabled false
}
finalizedBy 'jacocoTestCoverageVerification' // 추가
}
build.gradle.kts
tasks.test {
extensions.configure(JacocoTaskExtension::class) {
destinationFile = file("$buildDir/jacoco/jacoco.exec")
}
finalizedBy("jacocoTestReport")
}
tasks.jacocoTestReport {
reports {
// 원하는 리포트를 켜고 끌 수 있다.
html.isEnabled = true
xml.isEnabled = false
csv.isEnabled = false
// 각 리포트 타입 마다 리포트 저장 경로를 설정할 수 있다.
// html.destination = file("$buildDir/jacocoHtml")
// xml.destination = file("$buildDir/jacoco.xml")
}
finalizedBy("jacocoTestCoverageVerification")
}
설정이 다 끝났으면 test를 실행하자 ./gradlew test 명령어로 실행할 수도 있고, 인텔리제이 오른쪽에서 verification -> test로 실행할 수도 있다.
커버리지를 통과하면 build/reports/jacoco/test/html경로에 index.html 파일이 생성된거를 볼 수 있다.
해당 파일을 크롬 브라우저에서 열면 이런식으로 커버리지를 볼 수 있다. 현재는 작성한 테스트가 거의 없다.
REFERENCE
https://techblog.woowahan.com/2661/
https://seller-lee.github.io/java-code-coverage-tool-part2
https://blog.leocat.kr/notes/2020/02/02/jacoco-config-jacoco-for-kotlin-and-java-project
https://github.com/th-deng/jacoco-on-gradle-sample
'Test' 카테고리의 다른 글
JUnit5 테스트 병렬 실행 (2) | 2021.12.01 |
---|---|
코드 커버리지 적용(3) - 커버리지 제외 (0) | 2021.11.30 |
코드 커버리지 적용(1) - 커버리지란? (0) | 2021.11.30 |
Mockito && 스프링부트 테스트 관련 어노테이션 정리 (0) | 2021.11.17 |
무엇을 어떻게 테스트할 것인가 (feat : 권용근님) (0) | 2021.11.17 |