본문 바로가기

Backend/Java

[Java] JaCoCo를 활용하여 code coverage 측정하기

안녕하세요. 이번 포스팅에서는 JaCoCo라는 Java Code Coverage Library를 활용하여 코드 커버리지를 간단한 예제와 함께 측정해보겠습니다.

 

 

우선 Code Coverage란 무엇일까요?

 

Code Coverage

Code Coverage란 소프트웨어에서 test code가 본 코드를 얼마나 커버하고 있냐를 측정해주는 지표입니다. 테스트를 진행하였을 때 코드 자체가 몇% 나 실행되었느냐로 생각하실 수 있을 것입니다.

 

원래 원칙적으로 test code는 모든 시나리오에 대해서 설계되어야 합니다. 실제로 배포하는 서비스라면 더욱더 모든 시나리오를 커버하려 합니다. 하지만 현실적으로 내가 지금 작성한 테스트 케이스가 모든 케이스를 커버하는지를 객관적인 지표로 확인할 수 있는 방법 중에 하나가 Code Coverage입니다.

 

JaCoCo 

JaCoCo란 Java Code의 coverage를 측정하는 라이브러리입니다. 테스트를 실행하고, 그 결과를 html 파일이나 csv, xml 파일을 통해서 시각화해줍니다. 또한, 결과에 대한 기준치를 적용할 수도 있습니다.

 

JaCoCo를 활용하기 위해서 pom.xml파일을 다음과 같이 설정합니다.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>SpringBootLecture</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.8.2</version>
            </plugin>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.8.4</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>report</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

 

위와 같이 plugin에 JaCoCo가 설정되셨다면 command 창에 mvn clean verify를 입력해주시면 됩니다.

 

만약에 정상적으로 빌드가 되셨다면, 

 

위와 같이 target 디렉토리 하위에 site라는 디렉토리가 생기고 jacoco 디렉토리가 생길 것입니다.

 

Gradle을 사용하시는 분이라면, 아래의 글에 자세하게 설명되어 있어서 참고하시기 좋을 것 같습니다.

<Gradle 설정>

https://techblog.woowahan.com/2661/

 

Gradle 프로젝트에 JaCoCo 설정하기 | 우아한형제들 기술블로그

{{item.name}} 안녕하세요. 상품시스템팀에서 서버 개발(..새발)을 하고 있는 연철입니다. 프로젝트 세팅 중에 찾아보고 삽질했던 내용들이 도움이 될까 하여 남깁니다. JaCoCo는 Java 코드의 커버리지

techblog.woowahan.com

 

 

이제 간단하게 테스트해볼 코드를 작성해보겠습니다.

 

class Foo{
    public String hello(String name) {
        switch (name){
            case "hi":
                return "nice to meet you";
            case "ChanHo":
                return "Kim";
            default:
                return "hello method";
        }
    }

    public String callFoo() {
        return "call Foo Class";
    }
}

 

정말 간단한 Foo라는 class를 생성해보았습니다.

 

package mungboon;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class FooTest {

    @DisplayName("testWithChanHo")
    @Test
    public void fooTest() {
        Foo foo = new Foo();
        String args = "ChanHo";

        String ret = foo.hello(args);
        assertEquals("Kim", ret);
    }

}

Test Code를 통해 foo의 hello 메서드에 "ChanHo"만 테스트해보겠습니다.

 

테스트코드는 예상과 같이 큰 이상이 없이 실행됩니다.

 

이제 앞서보았단 jacoco 디렉토리 하위에 있는 index.html을 열어보겠습니다.

 

 

보시는 바와 같이 몇개의몇 개의 Instructions가 누락되었는지, 몇 개의 braches(분기 조건)이 누락되었는지 확인하실 수 있습니다.

 

더 자세하게 살펴보시면, 

정확히 어떤 Line이 누락되었는지 확인하실 수 있습니다.

 

이제 코드커버리지를 좀 높여보겠습니다.

 

Test Code를 다음과 같이 수정해보겠습니다.

 

package mungboon;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class FooTest {

    private final Foo foo = new Foo();

    @DisplayName("testWithChanHo")
    @Test
    public void fooTest() {
        String argsChanHo = "ChanHo";
        assertEquals("Kim", foo.hello(argsChanHo));
    }

    @DisplayName("testWithHi")
    @Test
    public void fooTestWithHi() {
        String argsHi = "hi";
        assertEquals("nice to meet you", foo.hello(argsHi));
    }

    @DisplayName("callTest")
    @Test
    public void fooCallTest() {
        String expectResult = "call Foo Class";
        assertEquals(expectResult, foo.callFoo());
    }

}

 

test code를 실행하시고 다시 mvn clean verify를 입력해주셔야 합니다.

 

보시는 바와 같이 코드 커버리지가 높아진 것을 확인하실 수 있습니다.

 

 

실제로 SpringApplication은 실행하지 않았기 때문에 바뀌지 않았고, 저희가 테스트 코드를 추가한 경우에 코드 커버리지가 높아진 것을 확인하실 수 있습니다.

 

추가로 커버리지 퍼센티지에 따라서 원하는 수치에 도달하지 못한 경우 빌드를 막아버리는 방법도 있습니다.

 

pom.xml 파일에 <build>에 다음 코드를 추가해주시면 수행 가능합니다.

 

<build>
        <plugins>
            ...
            <plugin>
                ...
                <executions>
 					....                 
                    <execution>
                        <id>jacoco-check</id>
                        <goals>
                            <goal>check</goal>
                        </goals>
                        <configuration>
                            <rules>
                                <rule>
                                    <element>PACKAGE</element>
                                    <limits>
                                        <limit>
                                            <counter>LINE</counter>
                                            <value>COVEREDRATIO</value>
                                            <minimum>0.50</minimum>
                                        </limit>
                                    </limits>
                                </rule>
                            </rules>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

 

보시면 0.5로 설정하면, 제 코드는 빌드가 되겠지만 만약에 저 수치를 0.8로 설정한다면,

 

 

위와 같이 Coverage check가 원하는 수치에 도달하지 못했다며, 빌드를 하지 못합니다.

 

 

오늘은 간단한 예제와 함께 JaCoCo 라이브러리를 사용해보는 포스팅을 진행해보았습니다.

 

*저의 글에 대한 피드백이나 지적은 언제나 환영합니다.  

'Backend > Java' 카테고리의 다른 글

[Java] Collections framework 이해하기  (0) 2021.07.17
[Java] 제네릭 이해하기  (0) 2021.07.17
[Java] static 제어자 이해하기  (0) 2021.07.04
[Java] 프록시 패턴이란?  (1) 2021.06.22
[JAVA] JVM과 JAVA code의 실행 과정  (5) 2021.06.10