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

์œ„์™€ ๊ฐ™์ด ํ”„๋กœ์ ํŠธ์˜ ์ตœ์ƒ๋‹จ ๊ฒฝ๋กœ์— ์ ์šฉํ•ด๋‘์–ด์•ผ ์ ์šฉ์ด ๋œ๋‹ค.
์ฐธ๊ณ ๋กœ ์•„์ง ๋ฉ”์„œ๋“œ ๋‹จ์œ„๋กœ ์ธก์ •์„ ํŒจ์Šคํ•˜๋Š” ๊ฒŒ ์—†์–ด์„œ, ์ปค๋ฒ„๋ฆฌ์ง€ ์ธก์ •์„ ์›ํ•˜์ง€ ์•Š๋Š” ํด๋ž˜์Šค๋ผ๋ฉด ํŒจํ‚ค์ง€ ๋‹จ์œ„๋กœ ๋ฌถ์–ด๋‘๋Š” ๊ฒŒ ์ข‹๋‹ค.

๋ชจ๋‘ ํ…Œ์ŠคํŠธ ํŒŒ์ดํŒ… ๐Ÿ’ช

Comments