Jacoco 적용하여 Test Coverage 확인하기

Sol's·2023년 1월 24일
0

팀프로젝트

목록 보기
5/25

Jacoco란?

Java code coverage tool

  1. 테스트를 실행하고, 그 결과를 html, csv, xml파일로 확인 할 수 있습니다.
  2. 테스트 결과가 내가 설정한 커버리지 기준을 만족하는지 확인하는 기능도 있습니다.

Jacoco 플러그인 추가

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.7.7'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'

    // jacoco
    id 'jacoco'
}

jacoco {
    toolVersion = '0.8.8'   // 이 부분 전체 추가
//  테스트결과 리포트를 저장할 경로 변경
//  default는 "$/jacoco"
//  reportsDir = file("$buildDir/customJacocoReportDir")
}

repostsDir = file()을 통해 Jacoco 리포트 결과물 디렉토리를 설정할 수 있습니다. 하지만 ,아래의 jacocoTestReport task에서 설정해 줄 수 있으므로 따로 적지 않았습니다.

플러그인을 추가하면 Gradle - Tasks - verification 에서 위사진의 두 항목이 추가되는것을 확인 할 수 있습니다.

JaCoCo Gradle 플러그인에는 jacocoTestReportjacocoTestCoverageVerification task가 있습니다.

jacocoTestReport: 바이너리 커버리지 결과를 사람이 읽기 좋은 형태의 리포트로 저장합니다.
html, xml, csv 같은 형태로 리포트를 생성할 수 있습니다.

jacocoTestCoverageVerification: 내가 원하는 커버리지 기준을 만족하는지 확인해 주는 task입니다.
브랜치 커버리지를 최소한 80% 이상으로 유지하고 싶다면, 이 task에 설정하면 됩니다. test task처럼 Gradle 빌드의 성공/실패로 결과를 보여줍니다.

test {
    useJUnitPlatform()				// JUnit5를 사용하기 위한 설정
    finalizedBy 'jacocoTestReport'  // Test 이후 커버리지가 동작하도록 finalizedBy 추가
}

useJUnitPlatform()는 test task에서는 JUnit을 사용한다고 Gradle에 알려주는 것입니다.
이 설정을 주지 않으면 jacocoTestReport taskjacocoTestCoverageVerification task를 스킵하게 됩니다.
실제로 테스트 자체가 돌지 않게 됩니다.

💡 Task 순서를 설정해 주어야 합니다

Test -> jacocoTestReport(결과 생성) -> jacocoTestCoverageVerification(기준체크)

위순서대로 진행되어야 정확한 결과를 알 수 있습니다.

Task 설정

test {
    useJUnitPlatform()				// JUnit5를 사용하기 위한 설정
    finalizedBy 'jacocoTestReport'  // Test 이후 커버리지가 동작하도록 finalizedBy 추가
}

jacoco {
    toolVersion = '0.8.8'
}

// 코드 커버리지 진행 후 결과를 리포트로 저장
jacocoTestReport {
    dependsOn test
    reports {
        html.enabled true
        xml.enabled true
        csv.enabled true

        // html 파일 위치 지정
        html.destination file('build/reports/myReport.html')
    }
    finalizedBy 'jacocoTestCoverageVerification'
}
  1. Test애서 test진행 후 jacocoTestReport가 실행될 수 있게 아래 처럼 설쟁해 주었습니다.
finalizedBy 'jacocoTestReport' 
  1. jacocoTestReport 에서는 결과를 저장하는 방식을 설정하였습니다.
    html,xml,csv를 true값으로 설정했고, html파일의 저장경로를 설정하였습니다.
    아래 코드처럼 jacocoTestReport진행 후 jacocoTestCoverageVerification가 실행되게 설정하였습니다.
finalizedBy 'jacocoTestCoverageVerification'
jacocoTestCoverageVerification {
	violationRules {
		rule {
			enabled = true // 활성화
			element = 'CLASS' // 클래스 단위로 커버리지 체크
			// includes = []

			// 라인 커버리지 제한을 80%로 설정
			limit {
				counter = 'LINE'
				value = 'COVEREDRATIO'
				minimum = 0.80
			}

			// 브랜치 커버리지 제한을 80%로 설정
			limit {
				counter = 'BRANCH'
				value = 'COVEREDRATIO'
				minimum = 0.80
			}

			// 빈 줄을 제외한 코드의 라인수를 최대 200라인으로 제한
			limit {
				counter = 'LINE'
				value = 'TOTALCOUNT'
				maximum = 200
			}
		}
	}
}

jacocoTestCoverageVerification는 테스트 검증의 기준을 설정해 줍니다.

Rule의 설정값

  1. enabled
    • 테스트 검증을 위한 해당 rule을 활성화할 것인지를 나타낸다. default는 true입니다.
  2. element
    • 테스트를 적용할 대상 혹은 테스트 측정 단위로 6개 유형이 존재.
    • Default값은 BUNDLE
      BUNDLE : 패키지 번들(프로젝트 모든 파일을 합친 것)
    • CLASS : 클래스
    • GROUP : 논리적 번들 그룹
    • METHOD : 메서드
    • PACKAGE : 패키지
    • SOURCEFILE : 소스 파일
  3. limit
    • rule의 상세 설정
  4. counter
    • 커버리지 측정의 최소 단위로 마찬가지로 6개의 유형이 존재.
    • Default는 INSTRUCTION : 가장 작은 측정 방식으로, Java 바이트코드를 읽습니다.
    • ✅BRANCH : 조건문(if, switch) 등의 분기 수에 대해 측정을 진행.
    • ✅LINE : 라인이 한 번이라도 실행되면 실행된 것으로 간주, 빈 줄은 제외.
    • CLASS : 클래스 내부의 메서드가 한 번이라도 실행된다면 실행된 것으로 간주.
    • COMPLEXITY : 코드 복잡도
    • METHOD : 메서드가 한 번이라도 실행되면 실행된 것으로 간주.
  5. value
    • 커버리지 측정을 보여주는 방식을 정하는 부분.
    • ✅Default는 COVEREDRATIO : 커버된 비율, 0부터 1사이의 숫자로 표현.
    • COVEREDCOUNT : 커버된 개수
    • MISSEDCOUNT : 커버되지 않은 개수
    • MISSEDRATIO : 커버되지 않은 비율, 0부터 1사이의 숫자로 표현.
    • TOTALCOUNT : 전체 개수
  6. minimum / maximum
    • jacocoTestCoverageVerification의 성공 여부를 결정하는 기준.
    • 예를 들어, minimum 0.8을 입력하면 80% 이상을 통과해야 성공.
    • maximum의 경우 코드의 라인 수를 제한할 때 사용.
  7. excludes
    • 커버리지를 측정할 때 제외할 클래스를 지정할 수 있습니다.

이제 실제 테스트가 필요없는 부분을 제외를 시켜줘야 합니다.

Test 제외

테스트 하지 않아도 되는 부분은 커버리지를 올리지 않아야 합니다.
spring-batch 등의 배치 설정 파일들이 있습니다.

jacocoTestReport에서 제외

💡 afterEvaluate`설정에서 디렉토리 경로를 통해 제외 할 수 있습니다.

와일드 카드 사용

*와 ?을 통해서 제외할 수 있습니다.
*일 땐, 0개 이상의 문자와 일치, **이면 0개 이상의 디렉토리와 일치한다는 문법입니다.
?은 단일 문자와 일치한다는 뜻입니다.

// 리포트 작성 시 특정 파일 제외
    afterEvaluate {
        classDirectories.setFrom(
                files(classDirectories.files.collect {
                    fileTree(dir: it, excludes: [
                            '**/PocoapocoApplication',
                            '**/*Request*',
                            '**/*Response*',
                            '**/Swagger*',
                            '**/PasswordEncoderConfig*',
                            '**/JpaAuditingConfig*'
                            // ...
                    ])
                })
        )
    }

jacocoTestCoverageVerification에서 제외

💡 exclude = [ ]를 사용해 제외 할 수 있습니다.
와일드 카드를 사용하는것은 동일하지만
패키지 + 클래스명 을 적어줘야 합니다.

excludes = [
                    '**.*PocoapocoApplication*',
                    '**.*Request*',
                    '**.*Response*',
                    '**.*Swagger*',
                    '**.*PasswordEncoder*',
                    '**.*JpaAuditing*'
            ]

Lombok 제외

@Getter, @Builder와 같은 코드도 제외시키는 것이 좋습니다.

방법은 프로젝트 루트 경로에 lombok.config를 만들고, Lombok이 달려있는 모든 클래스에 @Generated 어노테이션을 추가하는 설정을 다음과 같이 해줍니다.

lombok.addLombokGeneratedAnnotation = true

테스트를 실행하고 결과를 확인

프로젝트 폴더의 터미널에서 아래 코드를 사용 하면 테스트가 실행됩니다.

./gradlew test

또는 인텔리제이의 우측 상단에 Gradle 탭에서 Tasks - verification - test를 클릭해도 테스트가 실행됩니다.

이번 프로젝트에서는 TestCode를 아직 작성하지 않은 팀원들이 있어 테스트가 통과하지 못하는 경우가 있었습니다.

테스트가 한개라도 실패하게된다면 결과는 나오지 않습니다.
💡 이때 ./gradlew test 명령에 --continue 옵션을 추가해주면 이전 Task의 실패 여부와 상관없이 모든 Task를 수행할 수 있습니다.

코드 파일에서는 커버가 된 라인은 초록색, 놓친 부분은 빨간색으로 표시해 줍니다. 노란색은 모든 조건이 아닌 일부만 테스트된 라인입니다.

TestCode를 더 꼼꼼하게 작성하여 80%를 넘겨보겠습니다.

profile
배우고, 생각하고, 행동해라

0개의 댓글