코드 커버리지 적용() - JaCoCo

코드 커버리지 적용() - JaCoCo

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같은 형태로도 리포트를 생성할 수 있다.

: 바이너리 커버리지 결과를 사람이 읽기 좋은 형태의 리포트로 저장한다. 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 = "" dumpOnExit = true classDumpDir = null output = JacocoTaskExtension.Output.FILE address = "localhost" port = 6300 jmx = false } }

build.gradle.kts

tasks.getByName("test") { extensions.configure(JacocoTaskExtension::class) { isEnabled = true destinationFile = file("$buildDir/jacoco/$name.exec") includes = listOf() excludes = listOf() excludeClassLoaders = listOf() isIncludeNoLocationClasses = false sessionId = "" 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

from http://insight-bgh.tistory.com/521 by ccl(A) rewrite - 2021-11-30 20:01:36