Search
Duplicate
🧨

μ½”λ“œ 컀버리지 툴 적용기(feat. JaCoCo)

생성일
2022/10/13
νƒœκ·Έ
test
infra
λͺ©μ°¨

λ°°κ²½

μ €ν¬λŠ” ν”„λ‘œμ νŠΈμ˜ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 κ°œλ°œμ— λͺ°λ‘ν•˜λ©΄μ„œ ν…ŒμŠ€νŠΈμ— λ‹€μ†Œ μ†Œν™€ν–ˆμ§€λ§Œ 크게 문제둜 μΈμ‹ν•˜μ§€λŠ” μ•Šμ•˜μŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‹€κ°€ 개발 μ„œλ²„μ— λ°°ν¬ν•œ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 쀑 미처 ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ§€ λͺ»ν•œ λΆ€λΆ„μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•˜λŠ” 상황을 λ§ˆμ£Όν–ˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ νŒ€ λ‚΄λΆ€ 회의λ₯Ό 거쳐, ν…ŒμŠ€νŠΈμ— 관심을 가지고 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό 늘리기둜 κ²°μ •ν–ˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό λŠ˜λ €λ„ 기쑴에 있던 λ‘œμ§λ“€μ„ λͺ¨λ‘ μ»€λ²„ν•˜μ§€ λͺ»ν•΄ μœ μ‚¬ν•œ μ˜ˆμ™Έκ°€ λ°œμƒν•˜κ±°λ‚˜, μƒˆλ‘œμš΄ λ‘œμ§μ— λŒ€ν•΄ ν…ŒμŠ€νŠΈ 컀버λ₯Ό ν–ˆλŠ”μ§€ ν™•μ‹ ν•  수 μ—†λŠ” μƒν™©μ΄μ—ˆμŠ΅λ‹ˆλ‹€.
이에 ν…ŒμŠ€νŠΈ μ½”λ“œ 컀버리지λ₯Ό μ •λŸ‰μ μœΌλ‘œ μΈ‘μ •ν•˜κ³  λ¬Έμ„œν™”λ₯Ό ν•  수 μžˆλŠ” νˆ΄μ„ λ„μž…ν•˜κΈ°λ‘œ κ²°μ •ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

JaCoCo 채택 이유

JaCoCo 적용 μ΄μ „κΉŒμ§€λŠ” μΈν…”λ¦¬μ œμ΄μ˜Β Run with CoverageΒ κΈ°λŠ₯을 μ‚¬μš©ν•˜μ˜€μŠ΅λ‹ˆλ‹€. ν•΄λ‹Ή κΈ°λŠ₯은 μ‰½κ²Œ 접근이 κ°€λŠ₯ν•˜λ‹€λŠ” μž₯점이 μžˆμ—ˆμ§€λ§Œ, λ¬Έμ„œν™”κ°€ μ–΄λ ΅κ³  μΈ‘μ • 기쀀을 μ„ΈλΆ€ν™”ν•˜κΈ° νž˜λ“€μ–΄ JaCoCo λ„μž…μ„ κ²°μ •ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
JaCoCo λ₯Ό μ±„νƒν•œ μ΄μœ λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
1.
λ¬Έμ„œν™”κ°€ 쉽닀.
β€’
섀정을 톡해 μΈ‘μ •λœ κ²°κ³Όλ₯Ό html, xml λ“±μ˜ 파일 ν˜•νƒœλ‘œ λ§Œλ“€μ–΄λ‚Ό 수 μžˆμŠ΅λ‹ˆλ‹€.
2.
더 μžμ„Έν•˜λ‹€.
β€’
세뢀적인 μ„€μ •μœΌλ‘œ μΈ‘μ • λ‹¨μœ„, κΈ°μ€€ 등을 μ„ΈλΆ€μ μœΌλ‘œ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
3.
ν…ŒμŠ€νŠΈ 컀버λ₯Ό κ°•μ œν•  수 μžˆλ‹€.
β€’
μΈ‘μ •λœ κ²°κ³Όκ°€ μ„€μ •ν•œ λ‹¨μœ„ 및 기쀀에 λŒ€ν•œ κ·œμΉ™μ„ ν†΅κ³Όν•˜μ§€ λͺ»ν•˜λ©΄ build 에 μ‹€νŒ¨ν•˜κ²Œ λ©λ‹ˆλ‹€.

κΈ°λ³Έ μ„€μ •

μ•žμœΌλ‘œ 기술될 gradle 은 Groovy DSL 을 기반으둜 ν•©λ‹ˆλ‹€. 기본적인 섀정은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
plugins { id 'jacoco' } jacoco { toolVersion = '0.8.7' } jacocoTestReport { reports { html.enabled true xml.enabled true csv.enabled false } } jacocoTestCoverageVerification { violationRules { rule { element = 'CLASS' limit { counter = 'BRANCH' value = 'COVEREDRATIO' minimum = 0.90 } } } }
Groovy
볡사
β€’
plugin
β—¦
jacoco ν”ŒλŸ¬κ·ΈμΈμ„ μΆ”κ°€ν•©λ‹ˆλ‹€.
β—¦
ν”ŒλŸ¬κ·ΈμΈμ€ 이후에 κΈ°μˆ ν•  task 의 λ¬ΆμŒμž…λ‹ˆλ‹€. λΌμ΄λΈŒλŸ¬λ¦¬μ™€ 성격이 λΉ„μŠ·ν•˜κ³ , λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ½”λ“œμ—μ„œ μ‚¬μš©ν•  객체와 λ©”μ„œλ“œμ˜ 묢음이라면, plugin 은 gradle μ—μ„œ μ‚¬μš©ν•  λ©”μ„œλ“œμ˜ 묢음이라고 μƒκ°ν•˜λ©΄ λ©λ‹ˆλ‹€.
β€’
jacoco
β—¦
jacoco plugin 에 λŒ€ν•œ 섀정을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
β—¦
toolVersion 이외에도 reportsDirectory(μƒμ„±λœ 파일 디렉토리)등을 μ„€μ •ν•  수 있으며 기본값은 $buildDir/reports/jacocoΒ μž…λ‹ˆλ‹€.
β€’
jacocoTestReport, jacocoTestCoverageVerification
β—¦
jacoco plugin 에 ν¬ν•¨λ˜μ–΄μžˆλŠ” task μž…λ‹ˆλ‹€. 이후에 이 task λ₯Ό μ˜€λ²„λΌμ΄λ”©ν•˜μ—¬ μ‚¬μš©ν•  μ˜ˆμ •μž…λ‹ˆλ‹€.

κΈ°λ³Έ task

μ•žμ„œ μ–ΈκΈ‰ν–ˆλ“―μ΄, jacoco plugin μ—λŠ”Β jacocoTestReport 와 jacocoTestCoverageVerification 두 가지 task κ°€ μžˆμŠ΅λ‹ˆλ‹€.
β€’
jacocoTestReport
β—¦
λ°”μ΄λ„ˆλ¦¬λ‘œ 된 컀버리지 κ²°κ³Όλ₯Ό μ—¬λŸ¬ 파일 ν˜•νƒœλ‘œ μ €μž₯ν•©λ‹ˆλ‹€. html 은 κ²°κ³Ό λΆ„μ„μš©, xmlκ³Ό csvλŠ” μ™ΈλΆ€ 뢄석 λ„κ΅¬μ™€μ˜ 연동을 μœ„ν•΄ λ§Œλ“­λ‹ˆλ‹€.
β€’
jacocoTestCoverageVerification
β—¦
μ›ν•˜λŠ” 컀버리지 κΈ°μ€€(λ£°)을 μ„ΈμšΈ 수 μžˆμŠ΅λ‹ˆλ‹€. 기쀀을 μΆ©μ‘±ν•˜μ§€ λͺ»ν•œλ‹€λ©΄ build κ°€ μ‹€νŒ¨ν•˜κ²Œ λ©λ‹ˆλ‹€.
./gradlew test jacocoTestReport jacocoTestCoverageVerification
Bash
볡사
μœ„μ˜ λͺ…λ Ήμ–΄λ₯Ό μ‹€ν–‰ν•˜λ©΄ κΈ°λ³Έ directory 인 /build/reports/jacoco/test/html/index.html 에 파일이 μƒμ„±λœ 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.
κ·œμΉ™μ„ ν†΅κ³Όν•˜μ§€ λͺ»ν•˜λ©΄ build 에 μ‹€νŒ¨ν•©λ‹ˆλ‹€.

두 task λ₯Ό ν•œλ²ˆμ—!

task testCoverage(type: Test) { group 'verification' description 'Runs the unit tests with coverage' dependsOn(':test', ':jacocoTestReport', ':jacocoTestCoverageVerification') tasks['jacocoTestReport'].mustRunAfter(tasks['test']) tasks['jacocoTestCoverageVerification'].mustRunAfter(tasks['jacocoTestReport']) }
Groovy
볡사
testCoverage λΌλŠ” task λ₯Ό λ§Œλ“€κ³  ν•΄λ‹Ή task μ—μ„œ μœ„μ˜ 두 task λ₯Ό 묢을 수 μžˆμŠ΅λ‹ˆλ‹€.
β€’
group
β—¦
gradle 의 task λŠ” μ—¬λŸ¬κ°€μ§€ κ·Έλ£Ή(Application, Build, Build Setup, Documentation, Verification λ“±)으둜 λ‚˜λ‰©λ‹ˆλ‹€.
β—¦
이 κ·Έλ£Ήλ“€μ˜ task 듀이 유기적으둜 κ²°ν•©ν•˜κ³  μ‹€ν–‰λ˜μ–΄ λΉŒλ“œ λ˜λŠ” μŠ€ν”„λ§λΆ€νŠΈ 싀행을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. terminal μ—μ„œ μ•„λž˜μ˜ λͺ…λ Ήμ–΄λ₯Ό μž…λ ₯ν•˜λ©΄ 각각의 task 에 λŒ€ν•œ μ„€λͺ…을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.
./gradlew tasks
Bash
볡사
β€’
mustRunAfter
β—¦
mustRunAfter 으둜 νƒœμŠ€ν¬ μˆœμ„œλ₯Ό 지정해쀄 수 μžˆμŠ΅λ‹ˆλ‹€.
β—¦
mustRunAfter λŠ” dependsOn 보닀 ν›„μˆœμœ„μž…λ‹ˆλ‹€.Β μ΄μ™Έμ˜ λ©”μ„œλ“œλ“€μ€ λΉŒλ“œ 슀크립트 기초λ₯Ό μ°Έκ³ ν•΄μ£Όμ„Έμš”!
이 μ„€μ •μœΌλ‘œΒ ./gradlew testCoverageΒ λͺ…λ Ήμ–΄λ₯Ό μ‹€ν–‰ν•˜λ©΄Β ./gradlew test jacocoTestReport jacocoTestCoverageVerificationΒ λͺ…령어와 같은 싀행을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ„ΈλΆ€ μ„€μ •

jacocoTestCoverageVerification νƒœμŠ€ν¬μ—μ„œ 컀버리지 기쀀을 μžμ„Έν•˜κ²Œ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
λ‹€μŒμ€ 저희 λͺ¨λ½ νŒ€μ΄ 회의λ₯Ό 톡해 μ •μ˜ν•œ λ£°μž…λ‹ˆλ‹€.
tasks.named('jacocoTestCoverageVerification') { violationRules { rule { element = 'CLASS' limit { counter = 'BRANCH' value = 'COVEREDRATIO' minimum = 0.80 } limit { counter = 'LINE' value = 'COVEREDRATIO' minimum = 0.70 } limit { counter = 'METHOD' value = 'COVEREDRATIO' minimum = 0.60 } excludes = [ '**.*Formatter*', '**.*BaseEntity*', '**.*GithubOAuthClient*', '**.*MorakBackApplication*', '**.*Interceptor*', '**.*Extractor*', '**.RestSlackClient', '**.*Config' ] } rule { element = 'METHOD' limit { counter = 'LINE' value = 'TOTALCOUNT' maximum = 200 } } } }
Groovy
볡사
violationRules μ†μ„±μ—μ„œ rule 을 μ •μ˜ν•  수 있으며, μ—¬λŸ¬ 개의 rule 을 μ •μ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
β€’
element
β—¦
컀버리지λ₯Ό 체크할 기쀀을 μ„€μ •ν•©λ‹ˆλ‹€.
β—¦
κ°€λŠ₯ν•œ κ°’μœΌλ‘œλŠ” BUNDLE, PACKAGE, CLASS, GROUP, SOURCEFILE, METHOD κ°€ 있으며 κΈ°λ³Έ 값은 BUNDLE μž…λ‹ˆλ‹€.
β€’
counter
β—¦
컀버리지 μΈ‘μ •μ˜ μ΅œμ†Œ λ‹¨μœ„μž…λ‹ˆλ‹€.
β—¦
κ°€λŠ₯ν•œ κ°’μœΌλ‘œλŠ” INSTRUCTION, LINE, BRANCH, COMPLEXITY, METHOD, CLASS κ°€ 있으며 κΈ°λ³Έ 값은 INSTRUCTION μž…λ‹ˆλ‹€.
β€’
value
β—¦
컀버리지λ₯Ό μΈ‘μ •ν•  λ‹¨μœ„μž…λ‹ˆλ‹€.
β—¦
κ°€λŠ₯ν•œ κ°’μœΌλ‘œλŠ” TOTALCOUNT, MISSEDCOUNT, COVEREDCOUNT, MISSEDRATIO, COVEREDRATIO κ°€ 있으며 κΈ°λ³Έ 값은 COVEREDRATIO μž…λ‹ˆλ‹€.
μœ„μ˜ 3개λ₯Ό μ‘°ν•©ν•΄μ„œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
ex)
1.
PACKAGE, METHOD, COVEREDRATIO β†’ νŒ¨ν‚€μ§€μ˜ λ©”μ„œλ“œ μ»€λ²„λΉ„μœ¨
2.
METHOD, BRANCH, COVEREDRATIO β†’ λ©”μ„œλ“œμ˜ λΆ„κΈ° μ»€λ²„λΉ„μœ¨
3.
CLASS, LINE, TOTALCOUNT β†’ 클래슀의 라인 총 갯수
β€’
includes
β—¦
각각의 rule μ—μ„œ μ§€μ •λœ element λ₯Ό κΈ°μ€€μœΌλ‘œ, 포함할 element λ₯Ό 지정할 수 μžˆμŠ΅λ‹ˆλ‹€.
β—¦
κΈ°λ³Έ 값은 λͺ¨λ“  element μž…λ‹ˆλ‹€([*]).
β€’
excludes
β—¦
각각의 rule μ—μ„œ μ§€μ •λœ element λ₯Ό κΈ°μ€€μœΌλ‘œ, μ œμ™Έν•  element λ₯Ό 지정할 수 μžˆμŠ΅λ‹ˆλ‹€.
β—¦
κΈ°λ³Έ 값은 빈 list μž…λ‹ˆλ‹€.
β—¦
ant μŠ€νƒ€μΌλ‘œ 값을 지정할 수 μžˆμŠ΅λ‹ˆλ‹€.

λ©”μ„œλ“œ μ œμ™Έν•˜κΈ°

μœ„μ˜ rule 을 ν™œμš©ν•˜μ—¬ 클래슀 내뢀에 ν¬ν•¨λœ Β equals 와 같은 λ©”μ„œλ“œλ₯Ό μΈ‘μ •μ—μ„œ μ œμ™Έν•˜λ €κ³  ν–ˆλŠ”λ° λ¬Έμ œκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. rule μ—μ„œ exclude ν•  수 μžˆλŠ” ν•­λͺ©μ€Β elementΒ μ—μ„œ μ •μ˜λœ CLASSΒ μž…λ‹ˆλ‹€. κ·Έλž˜μ„œ ν•΄λ‹Ή rule μ—μ„œ exclude λ‘œλŠ” 클래슀의 λ©”μ„œλ“œλ₯Ό exclude 둜 μ œμ™Έν•  수 μ—†μ—ˆμŠ΅λ‹ˆλ‹€. 즉 element κ°€ 클래슀이면 클래슀만 μ œμ™Έν•  수 있고, element κ°€ λ©”μ„œλ“œμ—¬μ•Ό λ©”μ„œλ“œλ₯Ό μ œμ™Έν•  수 μžˆμŠ΅λ‹ˆλ‹€.
저희 ν”„λ‘œμ νŠΈμ—λŠ” μ„œλΉ„μŠ€ 둜직 상 equals 와 hashCode λ₯Ό μž¬μ •μ˜ν•œ 둜직이 μžˆλŠ”λ°, ꡳ이 ν…ŒμŠ€νŠΈν•  ν•„μš”κ°€ μ—†μ–΄μ„œ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ— μΆ”κ°€ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό ν…ŒμŠ€νŠΈν•˜μ§€ μ•ŠμœΌλ©΄ μ§€μ •ν•œ rule 의 BRANCH 와 METHODΒ μ—μ„œ κ±Έλ €, λΉŒλ“œμ— μ‹€νŒ¨ν•˜κ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€. ν…ŒμŠ€νŠΈ 컀버리지λ₯Ό μœ„ν•΄ ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό ν…ŒμŠ€νŠΈν•˜μ—¬ λΆˆν•„μš”ν•œ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό μΆ”κ°€ν•˜κΈ°λ³΄λ‹€λŠ”, ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό μΈ‘μ •μ—μ„œ μ œμ™Έν•˜λŠ” 방법을 μ°Ύμ•„λ³΄μ•˜μŠ΅λ‹ˆλ‹€. 저희가 κ²ͺ은 문제λ₯Ό λ§Žμ€ κ°œλ°œμžλ“€μ΄ μš”κ΅¬ν–ˆλŠ”μ§€, JaCoCo 0.8.2 λΆ€ν„°λŠ”
1.
'Generated' λΌλŠ” 단어가 이름에 포함 
2.
RetentionPolicy κ°€ 'CLASS' λ˜λŠ” 'Runtime'Β 
을 μΆ©μ‘±ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜μ΄ λΆ™μ–΄μžˆμœΌλ©΄ ν•΄λ‹Ή Target 은 JaCoCo μΈ‘μ •μ—μ„œ μ œμ™Έν•  수 μžˆλ‹€κ³  ν•©λ‹ˆλ‹€.
이에 따라 μœ„μ˜ 기쀀을 μΆ©μ‘±ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜μ„ λ§Œλ“€κ³ , ν…ŒμŠ€νŠΈκ°€ λΆˆν•„μš”ν•œ λ©”μ„œλ“œμ— λ§Œλ“  μ–΄λ…Έν…Œμ΄μ…˜μ„ λ‹¬μ•„μ£Όμ—ˆμŠ΅λ‹ˆλ‹€.
@Documented @Retention(RUNTIME) @Target({TYPE, METHOD}) public @interface Generated { }
Java
볡사
@Override @Generated public boolean equals(Object o) { // ... }
Java
볡사
λ‹¨μ μœΌλ‘œλŠ” μ„œλΉ„μŠ€ μ½”λ“œμ— ν…ŒμŠ€νŠΈ μ½”λ“œ 둜직이 λ“€μ–΄κ°„λ‹€λŠ” μ μ΄μ—ˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ΄λŸ¬ν•œ λ‹¨μ λ³΄λ‹€λŠ” ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ˜ μˆœλ„λ₯Ό λ†’μ΄λŠ” 것이 더 μ ν•©ν•˜λ‹€κ³  νŒλ‹¨ν•˜μ—¬ μœ„μ˜ μ–΄λ…Έν…Œμ΄μ…˜ 방식을 μ‚¬μš©ν•˜κΈ°λ‘œ κ²°μ •ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

lombok κ΄€λ ¨ μ œμ™Έν•˜κΈ°

저희 ν”„λ‘œμ νŠΈμ—μ„œλŠ” μž¬μ •μ˜ν•œ equals, hashcode λ©”μ„œλ“œ 뿐만 μ•„λ‹ˆλΌ NoArgsConstructor, Getter λ“±μ˜ lombok μ–΄λ…Έν…Œμ΄μ…˜λ„ μ΄μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 이에 따라 ν•΄λ‹Ή lombok κ΄€λ ¨ λ©”μ„œλ“œλ“€λ„ ν…ŒμŠ€νŠΈ 컀버리지에 μΈ‘μ •λ˜μ–΄ λΉŒλ“œμ— μ‹€νŒ¨ν•˜λŠ” κ²½μš°κ°€ μƒκ²ΌμŠ΅λ‹ˆλ‹€. 이에 따라 lombok κ³Ό κ΄€λ ¨λœ λ¬Έμ œλ„ μΈ‘μ •μ—μ„œ μ œμ™Έν•˜κΈ°λ‘œ κ²°μ •ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
lombok.addLombokGeneratedAnnotation = true
Plain Text
볡사
ν”„λ‘œμ νŠΈ 루트 디렉토리 ν•˜μœ„μ— lombok.config νŒŒμΌμ„ project 의 root path 에 μƒμ„±ν•˜κ³  μœ„μ™€ 같은 섀정을 ν•΄μ£Όμ—ˆμŠ΅λ‹ˆλ‹€. 이 섀정은 λͺ¨λ“  lombok 으둜 μƒμ„±λœ λ©”μ„œλ“œμ— λŒ€ν•΄ β€˜Generated’ μ–΄λ…Έν…Œμ΄μ…˜μ„ λΆ™μΈλ‹€λŠ” μ„€μ •μž…λ‹ˆλ‹€.

μ„€μ • 뢄석

μœ„μ™€ 같이 ν…ŒμŠ€νŠΈκ°€ λΆˆν•„μš”ν•œ λ©”μ„œλ“œμ™€ lombok κ΄€λ ¨ λ©”μ„œλ“œλ₯Ό μ œμ™Έν•˜λŠ” 것이 κ°€λŠ₯ν•œ μ΄μœ λŠ” lombok 의 λ©”μ„œλ“œ 생성 μ‹œμ κ³Ό, JaCoCo 의 μ½”λ“œ 컀버리지 μΈ‘μ • 방식에 μžˆμŠ΅λ‹ˆλ‹€.

lombok λ©”μ„œλ“œ 생성 μ‹œμ 

lombok 의 λ©”μ„œλ“œλŠ” complie μ‹œμ— 생성이 λ©λ‹ˆλ‹€(annotation processing). 이에 따라 μ»€μŠ€ν…€ν•œ μ–΄λ…Έν…Œμ΄μ…˜μΈ @Generated κ°€ 뢙은 λ©”μ„œλ“œλ‚˜ lombok λ©”μ„œλ“œλŠ” compile 된 이후 μƒμ„±λœ class 파일의 λ©”μ„œλ“œμ—@Generated κ°€ λΆ™μ–΄μžˆμŠ΅λ‹ˆλ‹€.

JaCoCo μΈ‘μ • 방식

JaCoCo λŠ” Java Agent 둜 싀행이 λ©λ‹ˆλ‹€. 이에 따라 λ°”μ΄νŠΈ μ½”λ“œλ₯Ό 직접 관리할 수 있으며, ν…ŒμŠ€νŠΈ μ‹€ν–‰ 쀑에 각각의 μ½”λ“œλ₯Ό λ³΄λ©΄μ„œ μ–΄λ–€ μ½”λ“œ 라인이 μˆ˜ν–‰λ˜μ—ˆλŠ”μ§€ ν™•μΈν•˜λ©΄μ„œ 컀버 λΉ„μœ¨μ„ μΈ‘μ •ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ 방식 덕뢄에 class νŒŒμΌμ— @Generated κ°€ 뢙은 λ©”μ„œλ“œλŠ” μΈ‘μ •μ—μ„œ μ œμ™Έν•  수 μžˆλŠ” κ²ƒμž…λ‹ˆλ‹€.

뢄석 κ²°κ³Ό

PR μ‹œ SonarQube 둜 μ½”λ“œ 정적 뢄석과 ν•¨κ»˜ JaCoCo 둜 μΈ‘μ •λœ 결과에 λŒ€ν•΄μ„œλ„ λΆ„μ„ν•˜μ—¬ 뢄석 κ²°κ³Όλ₯Ό PR λ§κΈ€λ‘œ μ•Œλ €μ€„ 수 μžˆλ„λ‘ ν•˜μ˜€μŠ΅λ‹ˆλ‹€. μ•žμ„œ μ„€μ •ν•œ 4개의 κ·œμΉ™μ„ ν†΅κ³Όν•˜μ§€ λͺ»ν•˜λ©΄ build 에 μ‹€νŒ¨ν•˜κ²Œ 되고, SonarQube μ—μ„œλ„ 전체적인 톡과 기쀀을 80% 둜 μž‘μ•„ 전체 μ½”λ“œμ— λŒ€ν•΄μ„œλ„ ν…ŒμŠ€νŠΈ 컀버리지에 λŒ€ν•΄ μΈ‘μ •ν•  수 μžˆλ„λ‘ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

μ°Έκ³