정적 분석 with Jacoco & SonarQube

Junseo Kim·2021년 8월 25일
2
post-thumbnail

Jacoco

자바 코드커버리지를 측정할 때 사용하는 오픈소스 라이브러리

  • 라인 커버리지 제공
  • 브랜치 커버리지(조건분기문의 Boolean expression이 참/거짓으로 모두 실행 되었는지) 제공
  • 커버리지 결과를 xml, html, csv 등의 파일로 저장가능
  • 기준을 설정해줘서 특정 커버리지 기준을 만족하는지 확인 가능

설정 방법

  1. 플러그인 추가
plugins {
    id 'jacoco'
}

jacocoTestCoverageVerification: 원하는 커버리지 기준을 만족하는지 확인해 주는 Task

jacocoTestReport: 커버리지 결과를 xml, html, csv 등의 파일로 저장

  1. Jacoco 플러그인 설정
jacoco {
    toolVersion = '0.8.5' 
    // reportsDir = ${project.reporting.baseDir}/jacoco - 따로 설정해 주지 않을 경우 기본 경로
}

0.8.0 버전부터 lombok 사용으로 생기는 @Getter, @Builder등을 테스트 커버리지에서 제외시키기 위한 설정을 적용할 수 있음.

  1. jacocoTestReport 설정

*소나큐브와 연동하기 위해서 xml로 파일로 만들어주기

jacocoTestReport {
    reports {
        html.enabled true // html 만들어 - 로컬에서 쉽게 보기 위함
        xml.enabled true // xml 만들어 - 소나큐브 연동 위함
        csv.enabled false // csv 안 만들어 

        // xml.destination file("${buildDir}/jacoco/result.xml") // 여기 저장할 것이라는 뜻.
    }
}

destination 설정을 하지 않으면, html은 build/reports/jacoco/test/html/index.html에 생기고, xml은 build/reports/jacoco/test/jacocoTestReport.xml에 생성된다.

  1. jacocoTestCoverageVerification 설정

rule.element: BUNDLE(default), CLASS, GROUP, METHOD, PACKAGE, SOURCEFILE

rule.limit.counter: INSTRUCTION(default),BRANCH, CLASS, COMPLEXITY, METHOD, LINE

rule.limit.value: COVEREDRATIO(default), COVEREDCOUNT, MISSEDCOUNT, MISSEDRATIO, TOTALCOUNT

jacocoTestCoverageVerification {
    violationRules {
        rule {
            enabled = true // 이 rule을 적용할 것이다.
            element = 'CLASS' // class 단위로

            // 브랜치 커버리지 최소 50%
            limit {
                counter = 'BRANCH'
                value = 'COVEREDRATIO'
                minimum = 0.50
            }

            // 라인 커버리지 최소한 80%
            limit {
                counter = 'LINE'
                value = 'COVEREDRATIO'
                minimum = 0.80
            }

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

            // 커버리지 체크를 제외할 클래스들
            excludes = []
        }
    }
}
  1. test task 설정
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
    }
}
  1. 최종
    test -> jacocoTestReport -> jacocoTestCoverageVerification 순으로 실행되어야한다.
    finalizedBy로 순서 지정
plugins {
    // ...
    id 'jacoco'
}

//...

test {
    // ...
    finalizedBy 'jacocoTestReport'
}

jacoco {
    toolVersion = '0.8.5'
}

jacocoTestReport {
    reports {
        html.enabled true
        xml.enabled true
        csv.enabled false

        xml.destination file("$buildDir/jacoco/jacoco.xml")
    }

    // 코드 커버리지 기준을 만족해야지 build 성공
    finalizedBy 'jacocoTestCoverageVerification'
}

jacocoTestCoverageVerification {
    violationRules {
        rule {
            enabled = true
            element = 'CLASS'

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

            limit {
                counter = 'LINE'
                value = 'COVEREDRATIO'
                minimum = 0.80
            }

            limit {
                counter = 'LINE'
                value = 'TOTALCOUNT'
                maximum = 300
            }

            excludes = []
        }
    }
}

SonarQube

버그, 코드 스멜, 보안 취약점을 발견할 목적으로 정적 코드 분석으로 자동 리뷰를 수행하기 위한 지속적인 코드 품질 검사용 오픈 소스 플랫폼

ubuntu에 설치

docker pull sonarqube
docker run -d --name sonarqube -p 9000:9000 sonarqube

설정

접속
http://[EC2 인스턴스 public ip]:9000

기본 계정
id: admin
password: admin

프로젝트 생성

토큰 발급

프로젝트에서 설정

  1. 플러그인 추가
plugins {
    id "org.sonarqube" version "3.3"
}
  1. 프로퍼티 설정
sonarqube {
    properties {
        property "sonar.projectKey", "dropthecode"
        property "sonar.host.url", "${sonarQube 인스턴스 ip:9000}"
        property "sonar.language", "java"
        property "sonar.sourceEncoding", "UTF-8"
        property "sonar.sources", "src/main/java"
        property "sonar.tests", "src/test/java"
        property "sonar.coverage.jacoco.xmlReportPaths", "${buildDir}/reports/jacoco/test/jacocoTestReport.xml" // jacoco xml 파일 위치
        property "sonar.java.binaries", "${buildDir}/classes"
        property "sonar.test.inclusions", "**/*Test.java"
        property "sonar.exclusions", "**/util/**, **/support/**, **/dto/**" // 제외할 클래스들 
    }
}
  • jacoco에서 exclude에 코드 커버리지 검사를 하지 않을 클래스를 설정해줘도, sonarQube에는 적용되지 않는다. 따라서 sonarQube에서도 해당 클래스를 제외하고 싶다면 sonar.exclusions 설정을 해줘야한다.

실행

test 실행 후 `./gradlew sonarqube -Dsonar.login=${위에서 발급 받은 토큰}

reference

1개의 댓글

comment-user-thumbnail
2022년 8월 9일

감사합니다!!

답글 달기