์šฐ๊ทœ์ด์ธ์šฐ์œค
Eager To Learn ๐ŸŒŒ
์šฐ๊ทœ์ด์ธ์šฐ์œค
์ „์ฒด ๋ฐฉ๋ฌธ์ž
์˜ค๋Š˜
์–ด์ œ

๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

  • ๐Ÿก ํ™ˆ
  • ๐Ÿš€ ๊นƒํ—ˆ๋ธŒ
  • โ›… ํƒœ๊ทธ ํด๋ผ์šฐ๋“œ
  • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (217)
    • ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป PS (170)
      • JAVA (82)
      • MYSQL (1)
      • Docker (2)
      • PYTHON (24)
      • LeetCode 150 (39)
      • Algorithm ๊ธฐ๋ฒ• (1)
      • ๋ฐ”ํ‚น๋… (21)
    • ๋ธ”๋กœ๊ทธ ์ด์‚ฌ (0)
    • Error (1)
    • CS (15)
      • DataBase (2)
      • OS (7)
      • Network (1)
      • Spring (1)
      • ์ž๋ฃŒ๊ตฌ์กฐ (3)
      • Java (1)
    • Learned (7)
      • Spring (7)
    • ๊ฐœ๋ฐœ์„œ์  (15)
      • ๊ฐ€์ƒ ๋ฉด์ ‘ ์‚ฌ๋ก€๋กœ ๋ฐฐ์šฐ๋Š” ๋Œ€๊ทœ๋ชจ ์‹œ์Šคํ…œ ์„ค๊ณ„ ๊ธฐ์ดˆ (1)
      • ์˜ค๋ธŒ์ ํŠธ - ์กฐ์˜ํ˜ธ (7)
      • ์นœ์ ˆํ•œ SQL ํŠœ๋‹ (7)
    • ํšŒ๊ณ  (2)
hELLO ยท Designed By ์ •์ƒ์šฐ.
์šฐ๊ทœ์ด์ธ์šฐ์œค
Learned/Spring

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ปค๋ฒ„๋ฆฌ์ง€ ๋ถ„์„ ๋„๊ตฌ Jacoco๋ฅผ ์ ์šฉํ•ด๋ณด์ž!

Learned/Spring

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ปค๋ฒ„๋ฆฌ์ง€ ๋ถ„์„ ๋„๊ตฌ Jacoco๋ฅผ ์ ์šฉํ•ด๋ณด์ž!

2023. 7. 28. 13:21

Jacoco ๋ž€?

Java Code Coverage ์˜ ์ค„์ž„๋ง๋กœ, ์ฝ”๋“œ ์ปค๋ฒ„๋ฆฌ์ง€ ๋ถ„์„์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.

 

โ“ ์ฝ”๋“œ ์ปค๋ฒ„๋ฆฌ์ง€๋ž€?

์†Œํ”„ํŠธ์›จ์–ด์˜ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์–ผ๋งˆ๋‚˜ ์ถฉ์กฑ๋˜์—ˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ง€ํ‘œ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

1. ๋ผ์ธ ์ปค๋ฒ„๋ฆฌ์ง€ : ์ฝ”๋“œ ํ•œ ์ค„์ด ํ•œ ๋ฒˆ ์ด์ƒ ์‹คํ–‰๋œ๋‹ค๋ฉด ์ถฉ์กฑ๋œ๋‹ค.

2. ๊ฒฐ์ • ์ปค๋ฒ„๋ฆฌ์ง€ : ๋ธŒ๋žœ์น˜ ์ปค๋ฒ„๋ฆฌ์ง€๋ผ๊ณ ๋„ ๋ถˆ๋ฆฐ๋‹ค. ๋ชจ๋“  ์กฐ๊ฑด์‹์˜ ๋‚ด๋ถ€ ์กฐ๊ฑด์ด true/ false ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋˜๋ฉด ์ถฉ์กฑํ•œ๋‹ค.

3. ์กฐ๊ฑด ์ปค๋ฒ„๋ฆฌ์ง€ : if ์กฐ๊ฑด๋ฌธ ์•ˆ์˜ ๊ฐœ๋ณ„ ์กฐ๊ฑด์‹์ด false ์ธ๊ฒฝ์šฐ์™€ true์ธ ๊ฒฝ์šฐ ๋ชจ๋‘ ์‹คํ–‰๋˜์—ˆ์„ ๋•Œ ์ถฉ์กฑํ•œ๋‹ค. ๊ฒฐ์ • ์ปค๋ฒ„๋ฆฌ์ง€๋ณด๋‹ค ๋” detailํ•œ ์ปค๋ฒ„๋ฆฌ์ง€์ด๋‹ค.

 


์ ์šฉํ•ด๋ณด์ž

 

์ ์šฉ ์ „ build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.2'
    id 'io.spring.dependency-management' version '1.1.2'
}

group = 'com'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.mysql:mysql-connector-j'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

 

 

plugin ์ถ”๊ฐ€

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.2'
    id 'io.spring.dependency-management' version '1.1.2'
	
    // ์ถ”๊ฐ€ ๋œ ๋ถ€๋ถ„
    id 'jacoco'
}

 

jacoco ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

 

 

jacoco ๋ฒ„์ „๊ณผ ๋ถ„์„ ๋ฆฌํฌํŠธ ๊ฒฝ๋กœ ์„ค์ •

jacoco {
    toolVersion = "0.8.10"
    reportsDirectory = layout.buildDirectory.dir('jacocoReport')
}

 

์œ„์™€ ๊ฐ™์ด ๋ถ„์„ ๋ฆฌํฌํŠธ๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜๋ฉด, build > jacocoReport ๋ผ๋Š” ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋˜๊ณ 

 

ํ•ด๋‹น ๋””๋ ‰ํ† ๋ฆฌ ์•ˆ์— ๋ฆฌํฌํŠธ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

 

 

test task ์‹คํ–‰ ํ›„ jacocoTestReport ์‹คํ–‰ ๋˜๊ฒŒ๋” ์„ค์ •

// ๊ธฐ์กด์— ์žˆ๋˜ ์•„๋ž˜ ์ฝ”๋“œ ์ œ๊ฑฐ
//
// tasks.named('test') {
//     useJUnitPlatform()
// }

test {
    finalizedBy jacocoTestReport
    useJUnitPlatform()
}

 

์œ„์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค.

 

finalizedBy jacocoTestReport๋Š” test task ์‹คํ–‰ ํ›„, jacocoTestReport task ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ๋” ํ•˜๋Š” ๊ตฌ๋ฌธ์ด๋‹ค.

 

ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ• ๋•Œ๋งˆ๋‹ค jacoco ๋ฆฌํฌํŠธ๊ฐ€ ์ƒ์„ฑ๋  ๊ฒƒ์ด๋‹ค. (์ œ์™ธํ•˜๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ์€ ์ œ์™ธํ•ด๋„ ๋œ๋‹ค. ๋Œ€์‹  ๋ถ„์„ ๋ฆฌํฌํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด ๋”ฐ๋กœ ์‹คํ–‰ํ•ด์•ผํ•œ๋‹ค.)

 

 

jacocoTestReport task ์„ค์ •

jacocoTestReport {

    dependsOn test

    reports {
        xml.required = false
        csv.required = false
        html.required = true
    }

    afterEvaluate {
        classDirectories.setFrom(
                files(classDirectories.files.collect {
                    fileTree(dir: it, excludes: [
                            '**/domain/**',
                            '**/global/**',
                            '**/*Application*'
                    ])
                })
        )
    }
    finalizedBy 'jacocoTestCoverageVerification'
}

 

dependsOn test ๋กœ test task ์‹คํ–‰ ๋’ค ์‹คํ–‰๋˜๋„๋ก ๋ช…์‹œํ•œ๋‹ค.

 

reports ๋Š” html ํŒŒ์ผ๋กœ๋งŒ ํ™•์ธํ•  ๊ฒƒ์ด๋ฏ€๋กœ html.required ๋งŒ true๋กœ ํ•œ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  afterEvaluate{ ... } ๊ตฌ๋ฌธ์˜ excludes : [ ... ] ์•ˆ์— ๋ถ„์„ ๋ฆฌํฌํŠธ์—์„œ ์ œ์™ธํ•  ํด๋ž˜์Šค๋ฅผ ์„ ํƒํ•œ๋‹ค.

 

๋‚˜๋Š” service ์ฝ”๋“œ์™€ controller ํด๋ž˜์Šค๋งŒ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ์ ๊ฒ€ํ•˜๊ธฐ ์œ„ํ•ด, ํ”„๋กœ์ ํŠธ ๋‚ด์˜ domain ยท global ๋””๋ ‰ํ† ๋ฆฌ ๊ทธ๋ฆฌ๊ณ  Application ํด๋ž˜์Šค ํŒŒ์ผ์„ ์ œ์™ธํ–ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ   finalizedBy 'jacocoTestCoverageVerification' ๋ฅผ ํ†ตํ•ด ๋‹ค์Œ ์ง„ํ–‰ํ•  task๋ฅผ ์„ค์ •ํ•œ๋‹ค.

 

 

jacocoTestCoverageVerification task ์„ค์ •

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

            // ๋ผ์ธ ์ปค๋ฒ„๋ฆฌ์ง€ ์ œํ•œ์„ 90%๋กœ ์„ค์ •
            limit {
                counter = 'LINE'
                value = 'COVEREDRATIO'
                minimum = 0.90
            }

            excludes = [
                    '**.*Application',
                    '**.domain.**',
                    '**.global.**'

            ]
        }

    }
}

 

์œ„ ๋ถ€๋ถ„์€, ์ปค๋ฒ„๋ฆฌ์ง€ ๊ธฐ์ค€์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

ํด๋ž˜์Šค ๋‹จ์œ„๋กœ ๋ผ์ธ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ์ตœ์†Œ 90% ๋งŒ์กฑ์‹œ์ผœ์•ผ ํ•˜๋Š” ์˜ต์…˜์„ ์„ค์ •ํ–ˆ๋‹ค.

 

๋˜ํ•œ, ์ปค๋ฒ„๋ฆฌ์ง€ ๊ฒ€์ฆ์—์„œ ์ œ์™ธํ•  ๊ฒฝ๋กœ๋„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. 

 

jacocoTestReport ์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ ํ‘œํ˜„์‹๊ณผ๋Š” ์•ฝ๊ฐ„ ์ฐจ์ด๊ฐ€ ์žˆ์œผ๋‹ˆ ์ฃผ์˜ํ•ด์•ผํ•œ๋‹ค.

 

์œ„์—์„œ ์„ค์ •ํ•œ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ๋งŒ์กฑํ•˜์ง€ ๋ชฉํ•˜๋ฉด ๋นŒ๋“œ ๊ณผ์ •์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋„๋ก ๋˜์–ด ์žˆ์–ด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์งœ๊ฒŒ๊ธˆ ๊ฐ•์กฐํ•  ์ˆ˜ ์žˆ๊ณ  ์•ˆ์ „ํ•œ ์ฝ”๋“œ๋ฅผ ์ง€ํ–ฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

 

 

์ ์šฉ ํ›„ build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.2'
    id 'io.spring.dependency-management' version '1.1.2'

    id 'jacoco'
}

group = 'com'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.mysql:mysql-connector-j'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    finalizedBy jacocoTestReport
    useJUnitPlatform()
}


jacoco {
    toolVersion = "0.8.10"
    reportsDirectory = layout.buildDirectory.dir('jacocoReport')
}


jacocoTestReport {

    dependsOn test

    reports {
        xml.required = false
        csv.required = false
        html.required = true
    }

    afterEvaluate {
        classDirectories.setFrom(
                files(classDirectories.files.collect {
                    fileTree(dir: it, excludes: [
                            '**/domain/**',
                            '**/global/**',
                            '**/*Application*'
                    ])
                })
        )
    }
    finalizedBy 'jacocoTestCoverageVerification'
}

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

            // ๋ผ์ธ ์ปค๋ฒ„๋ฆฌ์ง€ ์ œํ•œ์„ 90%๋กœ ์„ค์ •
            limit {
                counter = 'LINE'
                value = 'COVEREDRATIO'
                minimum = 0.90
            }

            excludes = [
                    '**.*Application',
                    '**.domain.**',
                    '**.global.**'

            ]
        }

    }
}

 


Jacoco Report ํ™•์ธ

 

์ด์ œ ๋‹ค์‹œ ๋นŒ๋“œ๋ฅผ ํ•˜๊ณ , ํ„ฐ๋ฏธ๋„์— 

./gradlew clean test

 

์œ„ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜

 

 

intellij ์—์„œ test task๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋ถ„์„ ๋ฆฌํฌํŠธ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

 

 

 

์„ค์ •ํ–ˆ๋˜ ๊ฒฝ๋กœ์— index.html ์ด๋ผ๋Š” ๋ฆฌํฌํŠธ๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๊ณ  ์—ด์–ด๋ณด๋ฉด

 

๋ผ์ธ ์ปค๋ฒ„๋ฆฌ์ง€์™€ ๋ธŒ๋žœ์น˜ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ๋ˆˆ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

ํด๋ฆญํ•ด์„œ ์ƒ์„ธ ํ™”๋ฉด์„ ๋“ค์–ด๊ฐ€๋ฉด, ์œ„์™€ ๊ฐ™์ด ๋ผ์ธ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 


ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

 

๋งŒ์•ฝ, test ๋ฆฌํฌํŠธ๊ฐ€ ์ƒ์„ฑ์ด ์ž˜ ์•ˆ๋˜๊ฑฐ๋‚˜ ๋ฆฌํฌํŠธ ๋‚ด์˜ ํ•œ๊ธ€์ด ๊นจ์ง€๊ฑฐ๋‚˜ ํ•˜๋Š” ๊ฒฝ์šฐ๋Š”

 

์‹ค์ œ ํ”„๋กœ์ ํŠธ๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ๋กœ์— ํ•œ๊ธ€๋กœ ๋œ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ํฌํ•จ๋˜์–ด์žˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

๋‚˜๋„ ๋ถ„์„ ๊ฒฐ๊ณผ ๋ฆฌํฌํŠธ์— ์ฃผ์„์œผ๋กœ ์จ๋†“์€ ํ•œ๊ธ€์ด ๊ณ„์† ๊นจ์ ธ์„œ ํ•œ์ฐธ์„ ํ•ด๊ฒฐํ•ด๋ณด๋ ค๋‹ค๊ฐ€

 

์‹ค์ œ ์ปดํ“จํ„ฐ์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์˜ ๊ฒฝ๋กœ๊ฐ€ ํ•œ๊ธ€๋กœ ๋œ ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์— ์žˆ์—ˆ๊ณ ,

 

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๋‹ˆ ํ•œ๊ธ€์ด ์ž˜ ๋‚˜์˜ค๊ฒŒ ๋˜์—ˆ๋‹ค.

  • Jacoco ๋ž€?
  • ์ ์šฉํ•ด๋ณด์ž
  • ์ ์šฉ ์ „ build.gradle
  • plugin ์ถ”๊ฐ€
  • jacoco ๋ฒ„์ „๊ณผ ๋ถ„์„ ๋ฆฌํฌํŠธ ๊ฒฝ๋กœ ์„ค์ •
  • test task ์‹คํ–‰ ํ›„ jacocoTestReport ์‹คํ–‰ ๋˜๊ฒŒ๋” ์„ค์ •
  • jacocoTestReport task ์„ค์ •
  • jacocoTestCoverageVerification task ์„ค์ •
  • ์ ์šฉ ํ›„ build.gradle
  • Jacoco Report ํ™•์ธ
  • ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…
'Learned/Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • Dispatcher Servlet์€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ• ๊นŒ?
  • Swagger API ์ ์šฉ ์‹œ, Controller ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด ๋”๋Ÿฌ์›Œ์ง„๋‹ค.. ๋ถ„๋ฆฌํ•ด๋ณด์ž
  • Dto Validation ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์— AOP๋ฅผ ์ ์šฉํ•ด๋ณด์ž!
  • @ControllerAdvice ๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์ผ๊นŒ?
์šฐ๊ทœ์ด์ธ์šฐ์œค
์šฐ๊ทœ์ด์ธ์šฐ์œค
๊ฐœ๋ฐœ์ž ๊ฟˆ๋‚˜๋ฌด

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”

๋‹จ์ถ•ํ‚ค

๋‚ด ๋ธ”๋กœ๊ทธ

๋‚ด ๋ธ”๋กœ๊ทธ - ๊ด€๋ฆฌ์ž ํ™ˆ ์ „ํ™˜
Q
Q
์ƒˆ ๊ธ€ ์“ฐ๊ธฐ
W
W

๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๊ธ€

๊ธ€ ์ˆ˜์ • (๊ถŒํ•œ ์žˆ๋Š” ๊ฒฝ์šฐ)
E
E
๋Œ“๊ธ€ ์˜์—ญ์œผ๋กœ ์ด๋™
C
C

๋ชจ๋“  ์˜์—ญ

์ด ํŽ˜์ด์ง€์˜ URL ๋ณต์‚ฌ
S
S
๋งจ ์œ„๋กœ ์ด๋™
T
T
ํ‹ฐ์Šคํ† ๋ฆฌ ํ™ˆ ์ด๋™
H
H
๋‹จ์ถ•ํ‚ค ์•ˆ๋‚ด
Shift + /
โ‡ง + /

* ๋‹จ์ถ•ํ‚ค๋Š” ํ•œ๊ธ€/์˜๋ฌธ ๋Œ€์†Œ๋ฌธ์ž๋กœ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ‹ฐ์Šคํ† ๋ฆฌ ๊ธฐ๋ณธ ๋„๋ฉ”์ธ์—์„œ๋งŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.