jacoco 반영

최준호·2023년 3월 31일
0

Spring

목록 보기
45/47
post-thumbnail

참고 달록의 Jacoco 적용기 (feat. Gradle)

📗 jacoco란?

test code를 작성하면 툴에서 test coverage를 확인할 수 있다. 하지만 이는 나만 확인할 수 있고 커버리지 수치가 낮아도 별 상관이 없다. 그냥 내 눈에 보이는 수치일 뿐

하지만 jacoco는 이를 문서화 해주고 커버리지 목표를 설저앟여 일정 수치가 넘어야지만 빌드를 가능하게끔 해주는 기능을 갖고 있다.

더 질 높은 코드를 작성하는 프로젝트를 진행하기 위해 jacoco를 도입해보자.

📄 적용하기

plugins {
    id 'jacoco'
}

// ...

jacoco {
    toolVersion = '0.8.8'
}

작성일 기준 가장 최신 버전이 0.0.8이더라 그래서 해당 버전으로 적용했다.

📄 사용하기

이제 테스트 코드를 실행해보자

테스트 코드가 종료된 뒤 jacoco 폴더가 build 폴더 아래에 생성된걸 확인할 수 있다.

그리고 해당 폴더 아래에는 test.exec 파일이 생성되었는데 이는 우리가 실행해서 읽어볼 수 없다. 해당 파일을 눈으로 볼수 있게 변경해야한다.

✅ gradle에 파일 변경 설정 넣기

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 기준을 낮춰서 설정해두었는데 저 부분을 꼭 올려야겠다라는 생각이 들었고 지금부터 테스트 기준을 계속해서 맞춰 나가면 더 좋은 코드를 작성할 수 있게될거 같다!

profile
코딩을 깔끔하게 하고 싶어하는 초보 개발자 (편하게 글을 쓰기위해 반말체를 사용하고 있습니다! 양해 부탁드려요!) 현재 KakaoVX 근무중입니다!

0개의 댓글