본문 바로가기
Test

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

by byeongoo 2021. 11. 30.

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/

 

Gradle 프로젝트에 JaCoCo 설정하기 | 우아한형제들 기술블로그

{{item.name}} 안녕하세요. 상품시스템팀에서 서버 개발(..새발)을 하고 있는 연철입니다. 프로젝트 세팅 중에 찾아보고 삽질했던 내용들이 도움이 될까 하여 남깁니다. JaCoCo는 Java 코드의 커버리지

techblog.woowahan.com

https://seller-lee.github.io/java-code-coverage-tool-part2

 

코드 분석 도구 적용기 - 2편, JaCoCo 적용하기

안녕하세요. 우아한테크코스 2기, 셀러리 컴퍼니에서 직고래 를 개발하고 있는 스티치입니다. 코드 분석 도구 적용기 - 1편, 코드 커버리지(Code Coverage)가 뭔가요? 에 이어서, 이번에는 프로젝트에

seller-lee.github.io

https://blog.leocat.kr/notes/2020/02/02/jacoco-config-jacoco-for-kotlin-and-java-project

 

[JaCoCo] Gradle 프로젝트에 JaCoCo 설정하기

이 글은 회사 기술블로그에 작성한 내용입니다.

blog.leocat.kr

https://github.com/th-deng/jacoco-on-gradle-sample

 

GitHub - th-deng/jacoco-on-gradle-sample: kotlin-jacoco-sample

kotlin-jacoco-sample. Contribute to th-deng/jacoco-on-gradle-sample development by creating an account on GitHub.

github.com