DevLog ๐ถ
[Gradle] Jacoco๋ฅผ ํ์ฉํ์ฌ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง ์ค์ ํ๊ธฐ ๋ณธ๋ฌธ
[Gradle] Jacoco๋ฅผ ํ์ฉํ์ฌ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง ์ค์ ํ๊ธฐ
dolmeng2 2023. 7. 23. 16:29๐ฑ ๋ค์ด๊ฐ๊ธฐ ์
์ฐ๋ฆฌ ํ์ CI ํ๋ก์ฐ ๊ณผ์ ์ค์์ Jacoco๋ฅผ ํ์ฉํ์ฌ ํ ์คํธ ๋ฆฌํฌํธ๋ฅผ ๋ฐํํ๊ณ , ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ฒดํฌํ๊ณ ์๋ค.
(ํ ์คํธ๋ฅผ ์ ๋ง ์ฒ ์ ํ๊ฒ ํ์๋ ์ทจ์ง์ธ๋ฐ, ํ์ ๋ชจ๋๊ฐ ํ ์คํธ๋ฅผ ์ ๋ง ๊ผผ๊ผผํ๊ฒ ์์ฑํด ์ฃผ์ ์ ์ข๋ค ๐)
CI์ ๋ํ ๊ธ์ ๋ค์์ ์์ ํ๊ฒ ๊ตฌ์ถ๋ ์ดํ์ ์์ฑํ๋ ๊ฒ ์ข์ ๊ฒ ๊ฐ์์, ์ค๋์ Jacoco์ ๋ํด์๋ง ๊ฐ๋ณ๊ฒ ์ง๊ณ ๋์ด๊ฐ๊ณ ์ ํ๋ค.
๐ฑ Jacoco ์ค์ ํ๊ธฐ
Jacoco๋, ํ
์คํธ ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ๋ถ์ํด์ฃผ๋ ์๋ฐ์ ๋ฌด๋ฃ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
Jacoco ํ๋ฌ๊ทธ์ธ์๋ JacocoTestReport์ JacocoTestCoverageVerification Task ๋ฑ์ด ์กด์ฌํ๋ค. (์ฌ๊ธฐ์๋ ์ด 2๊ฐ์ง๋ฅผ ์์ฃผ๋ก ์์๋ณด๋๋ก ํ์.)
- JacocoTestReport: ์ปค๋ฒ๋ฆฌ์ง ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํฌํธ๋ก ์ ์ฅํ๋ ์ญํ
- JacocoTestCoverageVerification: ์ํ๋ ์ปค๋ฒ๋ฆฌ์ง ๊ธฐ์ค์ ๋ง์กฑํ๋ ํ์ธํ๋ Task
๐ฌ build.gradle ์ค์ ํด์ฃผ๊ธฐ - JacocoTestReport
plugins {
id 'jacoco'
}
jacoco {
toolVersion = "0.8.10" // https://www.jacoco.org/jacoco/trunk/doc/changes.html
}
jacocoTestReport {
dependsOn test
reports {
html.required = true
xml.required = true
}
// QueryDSL QDomain ์ ์ธ์ํค๊ธฐ
def QDomains = []
for (qPattern in '**/QA'..'**/QZ') {
QDomains.add(qPattern + '*')
}
afterEvaluate {
classDirectories.setFrom(
// ๊ทธ ์ธ์ ๋งค์นญ๋๋ ํด๋์ค๋ ์ ์ธ ๋์
files(classDirectories.files.collect {
fileTree(dir: it, excludes: [
"co.kirikiri.domain.**.**",
"**/*Application*",
"**/*Config*",
"**/*Dto*",
"**/*Request*",
"**/*Response*",
"**/*Interceptor*",
"**/*Exception*"
] + QDomains)
})
)
}
// ๋ฆฌํฌํธ ์์ฑ ํ ์ปค๋ฒ๋ฆฌ์ง ์ฒดํฌ
finalizedBy jacocoTestCoverageVerification
}
jacocoTestCoverageVerification {
// QueryDSL QDomain ์ ์ธ์ํค๊ธฐ
def QDomains = []
// qPattern = "*.QA","*.QB","*.QC", ... "*.QZ"
for (qPattern in '*.QA'..'*.QZ') {
QDomains.add(qPattern + '*')
}
violationRules {
rule {
// rule ํ์ฑํ
enabled = true
// ํด๋์ค ๋จ์๋ก ๋ฃฐ ์ฒดํฌ
element = 'CLASS'
// ๋ผ์ธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ต์ 80% ๋ง์กฑ
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.80
}
// ๋ง์ฐฌ๊ฐ์ง๋ก ์ ๊ฑฐ ๋์ ์ง์
excludes = [
"co.kirikiri.domain.**.**",
"**.*Application*",
"**.*Config*",
"**.*Dto*",
"**.*Request*",
"**.*Response*",
"**.*Interceptor*",
"**.*Exception*"
] + QDomains
}
}
}
tasks.named('test') {
outputs.dir snippetsDir
useJUnitPlatform()
// test ์ํ ์ดํ ๋ฆฌํฌํธ ์์ฑ
finalizedBy jacocoTestReport
}
build.gradle ์ฝ๋๊ฐ ์๋นํ ๊ธธ๊ธฐ๋ ํ๋ฐ, ๊ทธ๋ ๊ฒ ์ด๋ ค์ด ๋ด์ฉ์ ์๋๋ค.
plugins {
id 'jacoco'
}
jacoco {
toolVersion = "0.8.10" // https://www.jacoco.org/jacoco/trunk/doc/changes.html
}
๋จผ์ , jacoco์ ๋ํ ํ๋ฌ๊ทธ์ธ์ ์ค์ ํด์ฃผ๋ ๋ถ๋ถ์ด๋ค.
ํ์ฌ ์ค๋ ์ท ๋ฒ์ ์ ์ธ ๊ฐ์ฅ ์ต์ ๋ฒ์ ์ด 0.8.10์ด๊ธธ๋ ์ด ๋ฒ์ ์ผ๋ก ์ค์น๋ฅผ ํด์ฃผ์๋ค.
jacocoTestReport {
reports {
html.required = true
xml.required = true
}
// QueryDSL QDomain ์ ์ธ์ํค๊ธฐ
def QDomains = []
for (qPattern in '**/QA'..'**/QZ') {
QDomains.add(qPattern + '*')
}
...
}
tasks.named('test') {
...
// test ์ํ ์ดํ ๋ฆฌํฌํธ ์์ฑ
finalizedBy jacocoTestReport
}
jacoco์์ ์ ๊ณตํ๋ ํ ์คํธ ๋ฆฌํฌํธ ๋ฐํ์ ์ํด ์ฌ์ฉํ๋ ๋ถ๋ถ์ด๋ค.
test๊ฐ ์คํ๋ ๋ค์์ ๋ฆฌํฌํธ๋ฅผ ๋ฐํํด์ผ ํ๊ธฐ ๋๋ฌธ์ finalizedBy์ ํตํด์ test ์คํ ์ดํ ๋์ํ๋๋ก ๋ง๋ค์๋ค.
finalizedBy๋ A task์ ์ฑ๊ณต๊ณผ ์คํจ์ ์๊ด์์ด A๊ฐ ๋๋์ผ B๊ฐ ์คํ๋๊ธฐ ๋๋ฌธ์ ์ฃผ์ํด์ ์ฌ์ฉํ๋๋ก ํ์.
(์ฑ๊ณตํด์ผ ์คํ๋๋๋ก ํ๋ ค๋ฉด dependsOn์ ์ฌ์ฉํ๋ค. ํ ์คํธ๊ฐ ์คํจํ๋๋ผ๋ ๋ฆฌํฌํธ๋ฅผ ๋ฐํํด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ฌ๊ธฐ์๋ finalizedBy๋ฅผ ํ์ฉํ์๋ค.)
์ดํ, xml๊ณผ html์ ๋ชจ๋์ ๋ํด์ ๋ฆฌํฌํธ๋ฅผ ๋ฐํํ๋๋ก ํ์๋ค.
์ฌ์ค ์ค์ ๋ก๋ html๋ง ๋ณด๋ ๊ฒฝ์ฐ๊ฐ ๋ง์์ ๊ผญ xml๊น์ง ํ์ง ์์๋ ๋๋ค๊ณ ์๊ฐํ๋ค.
...
// QueryDSL QDomain ์ ์ธ์ํค๊ธฐ
def QDomains = []
for (qPattern in '**/QA'..'**/QZ') {
QDomains.add(qPattern + '*')
}
afterEvaluate {
classDirectories.setFrom(
// ๊ทธ ์ธ์ ๋งค์นญ๋๋ ํด๋์ค๋ ์ ์ธ ๋์
files(classDirectories.files.collect {
fileTree(dir: it, excludes: [
"co.kirikiri.domain.**.**",
"**/*Application*",
"**/*Config*",
"**/*Dto*",
"**/*Request*",
"**/*Response*",
"**/*Interceptor*",
"**/*Exception*"
] + QDomains)
})
)
}
finalizedBy jacocoTestCoverageVerification
}
์ฐ๋ฆฌํ์ ํ์ฌ QueryDSL์ ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์ QueryDSL๋ก ์ธํด ์์ฑ๋ QDomain์ด๋ผ๋ ๊ฒ์ด ์กด์ฌํ๋ค.
์ด ์น๊ตฌ๋ค์ด ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง์ ๋ค์ด๊ฐ๊ฒ ๋๋ฉด 50% ์ดํ๋ก ์ปค๋ฒ๋ฆฌ์ง๊ฐ ์ ๋์ค๋ ๊ธฐ์ดํ ํ์์ด ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ qDomain์ ํจํด ๋งค์นญ์ ํตํด์ ์ ์ธ์์ผ์ฃผ์๋ค. ๋ํ, Dto๋ Config, Exception ๊ฐ์ ํด๋์ค๋ ํ ์คํธํ ํ์๊ฐ ์๋ค๊ณ ์๊ฐํด์ ์ ์ธํด๋์๋ค.
์ ์ฝ๋์์๋ ๋๋ฉ์ธ๊ณผ ์ธํฐ์ ํฐ๊น์ง ์๋๋ฐ, ์ธํฐ์ ํฐ๋ ์ถํ ์ ๊ฑฐํ ๊น ์๊ฐ ์ค์ด๋ค. (์ถฉ๋ถํ ํ ์คํธ๊ฐ ๊ฐ๋ฅํ๋๊น)
๋๋ฉ์ธ์ ๊ฒฝ์ฐ ํ ์คํธ๋ฅผ ์ง๊ณ ์๊ธฐ๋ ํ์ง๋ง, ์ฐ๋ฆฌ ํ์ ๊ณตํต์ผ๋ก ์ฌ์ฉ๋๋ ๋๋ฉ์ธ์ ํ์ด ํ๋ก๊ทธ๋๋ฐ์ ํตํด ์์ฑํ ๋ค์, ์ฌ์ ์ develop branch์ push๋ฅผ ํด๋๊ณ ๋ถ๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์งํํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ฐ์์ feature์์๋ ๋ณธ์ธ์ด ๋งก์ ๊ธฐ๋ฅ์ด ์๋๋ฉด ๋๋ฉ์ธ์ ๋ํ ํ ์คํธ๋ฅผ ์์ฑํ์ง ์๊ฒ ๋๋ค. ๊ทธ๋์ ๋๋ฉ์ธ๊น์ง๋ ์ปค๋ฒ๋ฆฌ์ง ๋ฒ์์ ๋์ง ์์๋๋ฐ, ๋์ค์ ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ์ ๋ถ ์์ฑํ๊ฒ ๋๋ฉด ์ถ๊ฐํ ๊น ์๊ฐ ์ค์ด๋ค.
๋ง์ง๋ง์ผ๋ก ๋ฆฌํฌํธ๋ฅผ ๋ฐํํ๊ณ ๋๋ฉด ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ค์ ํ ์ ์๋๋ก ํ์คํฌ๋ฅผ ์ฐ๊ฒฐํด๋์๋ค.
์ด๋ ๊ฒ ์์ฑ๋ ๋ฆฌํฌํธ์ ๊ฒฝ์ฐ ๊ธฐ๋ณธ์ ์ผ๋ก build/reports/jacoco/test/html ํ์์ ์์ฑ๋๋ค.
์ฌ๊ธฐ์ jacoco-resources ๋ฐ์ชฝ์ ์๋ index.html์ด๋ tests ์ชฝ์ index.html ๋๋ก ๋๋์ด์ ธ ์๋๋ฐ, ๋์ค๋ ์ ๋ณด๊ฐ ์ด์ง ๋ค๋ฅด๋ค.
์์์ ์๋ index.html์ด jacoco์ ์ํด์ ์์ฑ๋ ๋ฆฌํฌํธ์ด๊ณ , ์๋์ index.html์ gradle์์ ์๋์ผ๋ก ๋ง๋ค์ด์ฃผ๋ ๊ฒ์ผ๋ก ์๊ณ ์๋ค.
์์์ index.html์ ๊ฒฝ์ฐ ์์ ๊ฐ์ด ์ด๋ ํด๋์ค์์ ์ด๋ค ํ์ผ์ด ์ปค๋ฒ๋ฆฌ์ง์ ๋ถ์ถฉ์กฑํ๋์ง ๋์ค๊ฒ ๋๋ค.
ํ์์ ํ ์คํธ ๋ฆฌํฌํธ๋ ์์ ๊ฐ์ด ๊ฑธ๋ฆฐ ์๊ฐ์ด๋ ๋ช ๊ฐ์ ํ ์คํธ๊ฐ ์ฑ๊ณตํ๊ณ ์คํจํ์ง ํ์ธํ ์ ์๋ค.
๐ฌ build.gradle ์ค์ ํด์ฃผ๊ธฐ - JacocoTestCoverageVerification
jacocoTestCoverageVerification {
// QueryDSL QDomain ์ ์ธ์ํค๊ธฐ
def QDomains = []
// qPattern = "*.QA","*.QB","*.QC", ... "*.QZ"
for (qPattern in '*.QA'..'*.QZ') {
QDomains.add(qPattern + '*')
}
...
}
์ด๋ฒ์๋ ์ปค๋ฒ๋ฆฌ์ง์ ๋ํ ์ค์ ๋ถ๋ถ์ด๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก QDomain์ ๋ํด์๋ ์ธก์ ํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ ๊ฑฐํ๋๋ก ํ๋ค.
...
violationRules {
rule {
// rule ํ์ฑํ
enabled = true
// ํด๋์ค ๋จ์๋ก ๋ฃฐ ์ฒดํฌ
element = 'CLASS'
// ๋ผ์ธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ต์ 80% ๋ง์กฑ
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.80
}
// ๋ง์ฐฌ๊ฐ์ง๋ก ์ ๊ฑฐ ๋์ ์ง์
excludes = [
"co.kirikiri.domain.**.**",
"**.*Application*",
"**.*Config*",
"**.*Dto*",
"**.*Request*",
"**.*Response*",
"**.*Interceptor*",
"**.*Exception*"
] + QDomains
}
}
๋ค์์ผ๋ก๋ ์ธ๋ถ์ ์ธ ์ปค๋ฒ๋ฆฌ์ง ๋ฃฐ์ ๋ํด์ ์ง์ ํ๋ ๋ถ๋ถ์ด๋ค.
1. element: ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ฒดํฌํ ๊ธฐ์ค ์ ํ๊ธฐ
- BUNDLE: ํ๋ก์ ํธ์ ๋ชจ๋ ํ์ผ์ ํฉ์น ๊ฒ (๋ํดํธ)
- CLASS: ํด๋์ค
- GROUP: ๋
ผ๋ฆฌ์ ๋ฒ๋ค ๊ทธ๋ฃน
- METHOD: ๋ฉ์๋
- PACKAGE: ํจํค์ง
- SOURCEFILE: ์์ค ํ์ผ
๋๋ ํด๋์ค ๋จ์๋ก ์ค์ ํ๊ธฐ ์ํด CLASS๋ผ๊ณ ์ง์ ํด์ฃผ์์ผ๋ฉฐ, ๋๋ถ๋ถ ํด๋์ค ๋จ์๋ก ๋ง์ด ๋ณด์๋ ๊ฒ ๊ฐ๋ค.
์ข ๋ ๋นก์ธ๊ฒ ํ๊ณ ์ถ๋ค๋ฉด METHOD๋ก ํด๋ ๋ ๊ฒ ๊ฐ์๋ฐ, ๊ทธ๋ผ ๋๋ฌด ํ์ธํ๊ธฐ ํ๋ค์ง ์์๊น ์ถ๋ค.
2. counter: limit์ ํตํด ์ง์ ํ ์ ์์ผ๋ฉฐ, ์ปค๋ฒ๋ฆฌ์ง ์ธก์ ์ ์ํ ์ต์ ๋จ์. ์๋ฐ ๋ฐ์ดํธ ์ฝ๋์ ์คํ์ ๊ธฐ์ค์ผ๋ก ์ธก์ ๋๋ค.
- BRANCH: ์กฐ๊ฑด๋ฌธ ๋ฑ์ ๋ถ๊ธฐ ์
- CLASS: ํด๋์ค ์, ๋ด๋ถ ๋ฉ์๋๊ฐ ํ ๋ฒ์ด๋ผ๋ ์คํ๋์๋ค๋ฉด ์คํ๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ๋ค
- COMPLEXITY: ๋ณต์ก๋
- INSTRUCTION: Java ๋ฐ์ดํธ์ฝ๋ ๋ช
๋ น์ ์ (๋ํดํธ)
- METHOD: ๋ฉ์๋ ์, ๋ฉ์๋๊ฐ ํ ๋ฒ์ด๋ผ๋ ์คํ๋์๋ค๋ฉด ์คํ๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ
- LINE: ๋น ์ค์ ์ ์ธํ ์ค์ ์ฝ๋์ ๋ผ์ธ ์, ๋ผ์ธ์ด ํ ๋ฒ์ด๋ผ๋ ์คํ๋์๋ค๋ฉด ์คํ๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ
์ฌ๊ธฐ์ ๋ช ํผ์ผํธ์ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ๊ฐ์ก์ ๋ ๋น๋ ์คํจ๋ฅผ ํฐํธ๋ฆด ๊ฒ์ธ์ง ์ค์ ํ ์ ์๋ค.
๋๋ ์กฐ๊ธ ๋ ๋นก์ธ๊ฒ ํ๊ณ ์ถ์ด์ LINE ๊ธฐ์ค์ผ๋ก 80%์ ๊ธฐ์ค์ ์ก์๋ค.
์กฐ๊ธ ๋ ๋๋ํ๊ฒ ํ๊ณ ์ถ๋ค๋ฉด METHOD๋ก ํด๋ ๋ ๊ฒ ๊ฐ์๋ฐ, ์ด์ฐจํผ ๋ชจ๋ ๋ถ๊ธฐ์ ์ ๋ํด ํ ์คํธ๋ฅผ ์์ฑํ๋ ค๋ฉด ๋ผ์ธ์ผ๋ก ํ๋ ๊ฒ ๊ฐ์ฅ ๋์ ๊ฒ ๊ฐ๋ค๊ณ ์๊ฐํ๋ค.
3. value: limit์ ํตํด ์ง์ ํ ์ ์์ผ๋ฉฐ, ์ธก์ ํ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ด๋ ํ ๋ฐฉ์์ผ๋ก ๋ณด์ฌ์ค ๊ฒ์ธ์ง ์ ํ๋ค.
- COVEREDCOUNT: ์ปค๋ฒ๋ ๊ฐ์
- COVEREDRATIO: ์ปค๋ฒ๋ ๋น์จ, 0~1 ์ฌ์ด์ ์๋ก 1์ด 100% (๊ธฐ๋ณธ๊ฐ)
- MISSEDCOUNT: ์ปค๋ฒ๋์ง ์์ ๊ฐ์
- MISSEDRATIO: ์ปค๋ฒ๋์ง ์์ ๋น์จ, 0~1 ์ฌ์ด์ ์๋ก 1์ด 100%
- TOTALCOUNT: ์ ์ฒด ๊ฐ์
์ปค๋ฒ๋์ง ์์ ๋น์จ์ ๋ณด์ฌ์ฃผ๋ ๊ฒ๋ณด๋ค ์ปค๋ฒ๋ ๋น์จ์ ๋ณด์ฌ์ฃผ๋ ๊ฒ ํ์๋ค์ ์ฌ๊ธฐ ์ถฉ์ ์ ๋์์ด ๋ ๊ฒ ๊ฐ๋ค๊ณ ์๊ฐํ๋ค.
(20%๋ ๋ชปํ์ด์!๋ณด๋ค๋ 80% ํ์ผ๋๊น 100%๊น์ง ์ฑ์๋ด์~์ ๋๋์ด ๋ ์ข์ ๊ฒ์ฒ๋ผ?)
4. minimum: counter ๊ฐ์ value์ ๋ง๊ฒ ํํํ์์ ๋์ ์ต์๊ฐ, ์ด๋ฅผ ํตํด์ ์ปค๋ฒ๋ฆฌ์ง ํ๋จ์ ์ฑ๊ณต ์ฌ๋ถ๊ฐ ๊ฒฐ์ ๋๋ค๊ณ ๋ณผ ์ ์๋ค.
- ๊ธฐ๋ณธ์ ์ผ๋ก ํ๊ธฐํ ์๋ฆฌ์๋งํผ value๊ฐ ์ถ๋ ฅ๋๊ธฐ ๋๋ฌธ์ 90%์ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ํ๋ค๋ฉด 0.9๊ฐ ์๋ 0.90์ผ๋ก ์
๋ ฅํด์ค์ผ ํ๋ค. ์๋๋ฉด 0.9๋ก ์
๋ ฅํ๋ฉด 0.9x ๊ฐ์ ๋ชจ๋ 0.9๋ก ์ธ์ํ๋ค!
๋๋ ์ฐ์ 80% ์ ๋๋ก ์ค์ ํ์๋๋ฐ, 90%๊น์ง ์ฌ๋ฆด ์๊ฐ์ ์๋ค.
์ด๊ฑด ํ์๋คํํ ์๊ฒฌ์ ๋ฌผ์ด๋ณด๊ณ ์งํํด๋ณด๋ ค๊ณ ํ๋ค ๐ฎ
5. excludes: ์ปค๋ฒ๋ฆฌ์ง ์ธก์ ์ ์ ์ธํ ํด๋์ค๋ฅผ ์ง์ ํ ์ ์๋ค.
- ํจํค์ง ๋ ๋ฒจ์ ๊ฒฝ๋ก๋ก ์ง์ ํด์ผ ํ๋ฉฐ, ๊ฒฝ๋ก์๋ *์ ?์ ์ฌ์ฉํ ์ ์๋ค.
์ฌ๊ธฐ๋ ์๊น ํ ์คํธ ๋ฆฌํฌํธ ๋ฐํํ์ ๋์ ๊ฒฝ๋ก๋ ๋์ผํ๊ฒ ์ง์ ํด์ฃผ๋ฉด ๋๋ค.
๐ฌ ์คํํด๋ณด๊ธฐ
Test ์คํ์ ๊ฒฝ์ฐ ./gradlew test, ./gradlew clean build๋ก๋ ์คํ์ด ๊ฐ๋ฅํ๊ณ , intellij๋ฅผ ์ฌ์ฉํ๋ฉด gradle ๋๊ตฌ๋ฅผ ํ์ฉํ ์๋ ์๋ค!
๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด, ์๋์ ๊ฐ์ด ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ๋์ง ๋ชปํ์ ๋ ๋น๋ ์คํจ๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค.
์ด์ ํ ์คํธ ๋ฆฌํฌํธ ๋ณด๋ฉด์ ์ด๋๊ฐ ๋ถ์กฑํ์ง ๋ณด๊ณ ํ์ธํ๋ฉด์ ์งํํ๋ฉด ๋๋ค ใ ใ
์ฐธ๊ณ ๋ก, Lombok์ ์ด๋ ธํ ์ด์ ์ ๋ํ ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง๊ฐ 0%๋ก ๋์ค๋ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด์ lombok.config๋ฅผ ์ถ๊ฐ๋ก ์ค์ ํด์ฃผ์.
lombok.addLombokGeneratedAnnotation = true
์์ ๊ฐ์ด ํ๋ก์ ํธ์ ์ต์๋จ ๊ฒฝ๋ก์ ์ ์ฉํด๋์ด์ผ ์ ์ฉ์ด ๋๋ค.
์ฐธ๊ณ ๋ก ์์ง ๋ฉ์๋ ๋จ์๋ก ์ธก์ ์ ํจ์คํ๋ ๊ฒ ์์ด์, ์ปค๋ฒ๋ฆฌ์ง ์ธก์ ์ ์ํ์ง ์๋ ํด๋์ค๋ผ๋ฉด ํจํค์ง ๋จ์๋ก ๋ฌถ์ด๋๋ ๊ฒ ์ข๋ค.
๋ชจ๋ ํ ์คํธ ํ์ดํ ๐ช