photocard backend server 개발일기

SonarQube , JaCoCo 테스트 커버리지 측정하기

한둥둥 2025. 2. 6. 14:41

 

SonarQube 관련 글을 읽고 오시면 조금 더 이해하기 좋습니다. 


https://seounggyun.tistory.com/302

 

정적 코드 분석 AWS EC2 SonarQube 사용하여 Github Action CI 하기

🤗 정적 코드 분석 vs  동적 코드 분석정적 코드 분석은 코드가 실행 되기 전 소스 코드 또는 바이너리 코드를 분석해 코드를 직접 실행하지 않고 코드의 구조, 문법, 스타일, 잠재적인 버그, 코

seounggyun.tistory.com

해당 글은 JaCoCo 테스트 커버리지에 대한 내용이기에 SonarQube는 제외하고 글을 작성하겠습니다. 

 

해당 글을 작성한 계기는 SonarQube에서 단위 테스트 코드를 작성했음에도 불구하고, 테스트 커버리지를 인식하지 못하여 찾아보던 중, JaCoCo 와 연동해주어야 테스트 커버리지가 정상적으로 보이는 것을 알게되어 작성합니다. 

JaCoCo란?

JaCoCo(Java Code Coverage)는 Java 애플리케이션 코드 커버리지를 측정하는 도구다. 

단위 테스트 실행 시 얼마나 많은 코드가 실행되었는지를 분석하여 테스트의 효과성을 평가 

 

JaCoCo 플러그인 설정 

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.3'
    id 'io.spring.dependency-management' version '1.1.3'
    id "org.sonarqube" version "5.0.0.4638"
    id "jacoco"
}

// SonarQube 설정
sonar {
    properties {
        property "sonar.projectKey", "capo-project_capo-backend_9c8ca8d4-60b4-4f51-b018-261f74c69a56"
        property "sonar.projectName", "capo-backend"
        property "sonar.language", "java"
        property "sonar.sourceEncoding", "UTF-8"
        property "sonar.sources", "src/main"
        property "sonar.tests", "src/test"
        property "sonar.java.binaries", "${buildDir}/classes"
        property "sonar.test.inclusions", "**/*Test.java"
        property 'sonar.coverage.jacoco.xmlReportPaths', "${buildDir}/reports/jacoco/test/jacocoTestReport.xml"
    }
}

tasks.named('test') {
    useJUnitPlatform()
    finalizedBy 'jacocoTestReport'
}

// jacoco 정보
jacoco {
    toolVersion = "0.8.11"
    layout.buildDirectory.dir("reports/jacoco")
}

// jacoco Report 생성
jacocoTestReport {
    dependsOn test // test 종속성 추가

    reports {
        xml.required = true
        csv.required = false
        html.required = true
    }

    def QDomainList = []
    for (qPattern in '**/QA'..'**/QZ') { // QClass 대응
        QDomainList.add(qPattern + '*')
    }

    afterEvaluate {
        classDirectories.setFrom(files(classDirectories.files.collect {
            fileTree(dir: it, exclude: [
                    '**/dto/**',
                    '**/event/**',
                    '**/*InitData*',
                    '**/*Application*',
                    '**/exception/**',
                    '**/service/alarm/**',
                    '**/aop/**',
                    '**/config/**',
                    '**/MemberRole*'
            ] + QDomainList)
        }))
    }

//    finalizedBy 'jacocoTestCoverageVerification' // jacocoTestReport 태스크가 끝난 후 실행
}

// jacoco Test 유효성 확인
jacocoTestCoverageVerification {
    def QDomainList = []
    for (qPattern in '*.QA'..'*.QZ') { // QClass 대응
        QDomainList.add(qPattern + '*')
    }

    violationRules {
        rule {
            enabled = true // 규칙 활성화 여부
            element = 'CLASS' // 커버리지를 체크할 단위 설정

            // 코드 커버리지를 측정할 때 사용되는 지표
            limit {
                counter = 'LINE'
                value = 'COVEREDRATIO'
                minimum = 0.30
            }

            limit {
                counter = 'BRANCH'
                value = 'COVEREDRATIO'
                minimum = 0.30
            }

            excludes = [
                    '**.dto.**',
                    '**.event.**',
                    '**.*InitData*',
                    '**.*Application*',
                    '**.exception.**',
                    '**.service.alarm.**',
                    '**.aop.**',
                    '**.config.**',
                    '**.MemberRole*'
            ] + QDomainList
        }
    }
}

 

 

JaCoCo 테스트 지정하기 

tasks.named('test') {
    useJUnitPlatform()
    finalizedBy jacocoTestReport
}

 

 

SonarQube 분석 실행하기 

./gradlew build sonar