๐ฑ ๋ฌธ์ ์ํฉ
์ด์ ์ ๋ฉํฐ๋ชจ๋ + JaCoCo Report Aggregation์ ์ฌ์ฉํ์ฌ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ํ์ธํ๊ณ ๊ฒ์ฆํ๋ ๊ธฐ๋ฅ์ ์ ์ฉํด ๋ณด์๋ค.
๊ฐ ๋ชจ๋์์์ ๊ฒฐ๊ณผ ๋ณด๊ณ ์๋ฅผ ์ง๊ณํ ์ข ํฉ ๋ณด๊ณ ์๋ฅผ ์์ฑํ๋ ๋ฐ๋ ์ฑ๊ณตํ์ง๋ง ์ง๋ฉดํ๊ฒ ๋ ๋ ๋ค๋ฅธ ๋ฌธ์ ์ ์ด ์์๋ค.
๊ฐ๋จํ๊ฒ ์ค๋ช ํ์๋ฉด ๋ด ํ๋ก์ ํธ์๋ app, admin, domain ๋ชจ๋์ด ์๋๋ฐ ๋๋ฉ์ธ ๋ชจ๋์ ๋ฉ์๋ ํ ์คํธ๊ฐ ๋ค๋ฅธ ๋ชจ๋(app ๋๋ admin ๋ชจ๋)์์ ์คํ๋์ด ๋๋ฉ์ธ ๋ชจ๋ ์์ฒด์ ์ปค๋ฒ๋ฆฌ์ง๊ฐ ๋ฎ๊ฒ ๋์ค๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
JaCoCo๋ ๊ฐ ๋ชจ๋๋ณ๋ก ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ๊ณ์ฐํ๋๋ฐ, ๋๋ฉ์ธ ๋ชจ๋์ ์ฝ๋๊ฐ ๋ค๋ฅธ ๋ชจ๋์ ํ ์คํธ์์๋ง ์คํ๋์ด JacocoTestCoverageVerification ๋จ๊ณ์์ ๋๋ฉ์ธ ๋ชจ๋์ ์ปค๋ฒ๋ฆฌ์ง ๊ธฐ์ค์ ์ถฉ์กฑํ์ง ๋ชปํด ๋น๋๊ฐ ์คํจํ๊ฒ ๋์๋ค.
Rule violated for class Bid: lines covered ratio is 0.13, but expected minimum is 0.80
Rule violated for class User: lines covered ratio is 0.36, but expected minimum is 0.80
...
์ผ์ชฝ์ ๋๋ฉ์ธ ๋ชจ๋์ ๋ณด๊ณ ์, ์ค๋ฅธ์ชฝ์ ์ ์ฒด ๋ชจ๋ ์ข ํฉ ๋ณด๊ณ ์์ด๋ค. ์ด์ฒ๋ผ ๊ฐ์ ์ฝ๋๋ฅผ ํ ์คํธํ์์๋ ๋ถ๊ตฌํ๊ณ , ๋๋ฉ์ธ ๋ชจ๋์ ์ปค๋ฒ๋ฆฌ์ง๊ฐ ๋ฎ๊ฒ ๋์ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๐ฑ ํด๊ฒฐ ๋ฐฉ์
๋ด๊ฐ ์๊ฐํด ๋ธ ๋ฐฉ๋ฒ์ ๋ ๊ฐ์ง๊ฐ ์์๋ค. ์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ์ด์ฉ ์ ์์ด ๋๋ฉ์ธ ๋ชจ๋ ์์ฒด์์ ๋ฉ์๋๋ค์ ์ง์ ํ ์คํธํ๋ ๋จ์ ํ ์คํธ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ.. ๋ ๋ฒ์งธ ๋ฐฉ๋ฒ์ JaCoCo์ ์ค์ ์ ์กฐ์ ํด ๋ค๋ฅธ ๋ชจ๋์ ํ ์คํธ ์คํ ๊ฒฐ๊ณผ๋ ๋๋ฉ์ธ ๋ชจ๋์ ์ปค๋ฒ๋ฆฌ์ง์ ํฌํจ๋๋๋ก ํ๋ ๊ฒ์ด์๋ค.
์ด๋ฏธ ๋ค๋ฅธ ๋ชจ๋์์ ํ ์คํธ๋ ์ฝ๋์ ๋ํด ์ค๋ณต ํ ์คํธ๋ฅผ ์์ฑํ๋ ๊ฒ์ ๋นํจ์จ์ ์ด๋ผ ์๊ฐํ๊ณ , ์คํ๋ ค ๋ค๋ฅธ ๋ชจ๋์ ํ ์คํธ ์คํ ๊ฒฐ๊ณผ๋ฅผ ์ปค๋ฒ๋ฆฌ์ง์ ํจ๊ป ๋ฐ์ํ๋ ๊ฒ์ด ์ค์ ์ฌ์ฉํ๋ ์๋๋ฆฌ์ค์ ๋ ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ ๊ฒ์ด๋ผ ์๊ฐํ์ฌ JaCoCo์ ์ค์ ์ ์กฐ์ ํ๋ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํด ๋ณด๊ธฐ๋ก ํ๋ค.
subprojects {
apply plugin: 'java'
apply plugin: 'jacoco'
jacoco {
toolVersion = '0.8.12'
}
test {
finalizedBy 'jacocoTestReport'
}
jacocoTestReport {
...
}
jacocoTestCoverageVerification {
enabled = false // JaCoCo ๊ฒ์ฆ ๋นํ์ฑํ
}
}
์ฐ์ ๊ฐ ๋ชจ๋์์ jacocoTestCoverageVerification ํ์คํฌ๋ฅผ ๋นํ์ฑํํ๋ค.
project(':support:jacoco') {
apply plugin: 'jacoco-report-aggregation'
testCodeCoverageReport {
...
}
...
task jacocoRootCoverageVerification(type: JacocoCoverageVerification) {
dependsOn testCodeCoverageReport
// ์ปค๋ฒ๋ฆฌ์ง ์ธก์ ํ ์์ค ๋๋ ํ ๋ฆฌ ์ง์
// ๋ชจ๋ ์๋ธ ํ๋ก์ ํธ์ ์์ค ๋๋ ํ ๋ฆฌ ํฌํจ
sourceDirectories.setFrom(files(allProjects
.collect { it.sourceSets.main.allSource.srcDirs }))
// ์์ค ๋๋ ํ ๋ฆฌ ๋ด ํด๋์ค๋ฅผ ์ปดํ์ผ ํ ๊ฒฐ๊ณผ์ธ *.class ํ์ผ์ด ์๋ ๋๋ ํ ๋ฆฌ๋ฅผ ์ง์
// ๊ฐ ์๋ธ ํ๋ก์ ํธ์ ๋น๋ ๋๋ ํ ๋ฆฌ ๋ด์ ํด๋์ค ํ์ผ
classDirectories.setFrom(files(allProjects
.collect { it.fileTree(dir: "${it.buildDir}/classes/java/main", exclude:
Qdomains + excludeFromCoverage.stream()
.map(s -> s + ".class")
.collect(Collectors.toList())) }))
// ๋ชจ๋ ์๋ธ ํ๋ก์ ํธ์์ ์์ฑ๋ JaCoCo ์คํ ๋ฐ์ดํฐ ํฌํจ
executionData.setFrom(files(allProjects.collect { it.jacocoTestReport.executionData }))
violationRules {
rule {
enabled = true
element = "CLASS"
limit {
counter = "LINE"
value = "COVEREDRATIO"
minimum = 0.80
}
excludes += Qdomains.stream()
.map(s -> s.replace("/", "."))
.collect(Collectors.toList()) +
excludeFromCoverage.stream()
.map(s -> s.replace("/", "."))
.collect(Collectors.toList())
}
}
}
check.dependsOn jacocoRootCoverageVerification
}
jacocoRootCoverageVerification ํ์คํฌ๋ ๋ชจ๋ ์๋ธ ํ๋ก์ ํธ์ ์์ค ๋๋ ํ ๋ฆฌ, ํด๋์ค ํ์ผ, JaCoCo ์คํ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ์ฌ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ธก์ ํด ๊ฐ ๋ชจ๋์ ํ ์คํธ ๊ฒฐ๊ณผ๋ฅผ ์ข ํฉํ ์ ์ฒด ์ปค๋ฒ๋ฆฌ์ง ๋ณด๊ณ ์๋ฅผ ์์ฑํ๋ค. ๊ทธ ํ rule์ ์ง์ ํด ์ปค๋ฒ๋ฆฌ์ง ๊ธฐ์ค์ ๋ง์กฑํ๋์ง ํ์ธํ๋ค. ์ด๋ ๊ฒ ์์ ํ ๊ฒฝ์ฐ ๋ค๋ฅธ ๋ชจ๋์์ ์ํ๋ ํ ์คํธ ๊ฒฐ๊ณผ๋ ๋๋ฉ์ธ ๋ชจ๋์ ์ปค๋ฒ๋ฆฌ์ง์ ๋ฐ์๋๊ธฐ ๋๋ฌธ์ ์ค๋ณต ํ ์คํธ๋ฅผ ์์ฑํ ํ์ ์์ด ์ ์ฒด์ ์ธ ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ฒ์ฆํ ์ ์๊ฒ ๋๋ค.