[JUnit] Spring / Spring Boot, 테스트 코드를 작성하는 방법

안녕하세요. 최근에 백기선님의 유튜브를 자주 보곤합니다.

그 중에서는 더 나은 개발자로 성장하는 팁이라는 주제로 사연을 소개하면서 스토리텔링을 해주시는걸 자주 듣곤 하는데요. 그 팁중 하나로 테스트코드를 잘 작성하는 연습을 하는 개발자가 좋다는 이야기를 넌지시 들었어요. 

 

https://www.youtube.com/watch?v=s_Zdl28NEM4&t=131s

 

저는 테스트 코드를 주로 JUnit을 사용하고 있고, 개인적으로나 회사업무에서나 JUnit을 사용하여 테스트 코드를 짜면서 개발을 하고 있죠. 그래서 나름 내가 좋은 방향으로 가고 있구나 안심을 하면서 영상도 즐기면서 시청했었습니다.

 

그러던 중 댓글에서 "테스트코드가 뭐죠? 어떻게 짜는거죠?" 라는 댓글이 하나가 보이더라구요.

불과 몇달전까지만해도 테스트코드를 저도 몰랐으니까 그러려니 했어요.. 그런데 생각보다 주변 개발자중에서 테스트코드를 짜면서 개발하는 분이 많지는 않았던 것 같더라구요.

 

실질적으로 업무로 접하는 경우가 아니라면 저도 몰랐을거라고 생각이 되구요.

 

그래서 오늘은 처음으로 테스트 코드를 작성할 때, 그 테스트 라이브러리중 JUnit을 사용할 때 어떻게 시작하는가에 대해서 포스팅 해보려고 합니다.

 

실습입니다.!

 

JUnit 테스트 코드

JUnit 테스트는 스프링 부트에는 기본적으로 내재되어 있습니다. 저는 스프링부트를 이용하여 많이 개발을 하기 때문에 스프링 Starter 프로젝트를 생성하였습니다. 디펜던시는 롬복과 스프링웹개발정도 추가하였습니다. 매우 기본적인 디펜던시입니다.

 

프로젝트 구조

Score 점수에 대한 정보를 가지는 인터페이스
@FunctionalInterface
public interface Scoreable {
    int getScore();
}
Score에 대한 정보를 Collection 형태로 구현한 클래스
import java.util.ArrayList;
import java.util.List;

public class ScoreCollection {

    private List<Scoreable> scoreables = new ArrayList<>();

    public void add(Scoreable scoreable) {
        this.scoreables.add(scoreable);
    }

    public int getAverage() {
        int total = this.scoreables.stream().mapToInt(Scoreable::getScore).sum();
        return total / scoreables.size();
    }
}

- ScoreCollection에 add 메소드로 Scoreable에 대한 구현체를 저장하고, 평균을 내는 기능을 가진 Collection 클래스입니다.

- 참고로 ScoreCollection은 절대!!! Scoreable의 구현체가 아닙니다. 구현체들을 저장하는 공간이 될 것이고, 구현체들을 이용한 add, getAverage 기능이 있는 클래스일 뿐입니다.

 

이에 대한 테스트코드를 소개하겠습니다.

import com.example.junittest.class1.ScoreCollection;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.MatcherAssert.assertThat;

@SpringBootTest
public class Class1Tests {

    @Test
    public void averageTest() {
    //given
        ScoreCollection scoreCollection = new ScoreCollection();
        scoreCollection.add(() -> 5);
        scoreCollection.add(() -> 7);
        
    //when
        int average = scoreCollection.getAverage();

    //then
        assertThat(average).isEqualTo(6);
        assertThat(average, equalTo(6));
    }
}

- 크게 given(준비), when(실행), then(단언, 결과확인) 으로 이루어집니다. 

- [given] 단계에서는 테스트에 필요한 데이터들을 셋팅하는 단계입니다.

- [when] 단계에서는 직접 실행하는 단계입니다. 사실상 add() 메소드 조차 여기에 포함될 수 있겠네요. 이부분은 애매하므로 return 값이 있는 getAverage 메소드에서만 when이라 칭하겠습니다. 참고로 when 에는 어떠한 메소드 모듈이 들어갈 수도 있고, API에 대한 테스트가 진행될 수 있습니다.

- [then] 단계에서는 단언문(assert, assertThat 등)을 통해 success, fail 결과를 유도, 판단하는 단계입니다.

 

 

내가 JUnit을 이용하여 현재 사용하는 정도

현재는 회사 업무에서 API를 작성하면 테스트코드를 통해 Spring Restdoc을 돌려서 API 문서를 만들고 문서용 git에 (프론트 개발자분들과 공유하는) API 문서 공유git(정도라고 해야할까요?)에 업데이트하는 용도로 사용하고 있습니다.

대부분의 테스트는 API 테스트에 가깝고 아직까지 좀더 완성된 고립된(서비스로직까지 테스트하는) TDD(Test-Driven-Development)는 아닌 형태로 느껴지긴 합니다.

 

하지만 테스트코드를 작성했을 때와 작성하지 않고 스스로를 믿으며...? 코딩을 했을때와는 에러/실수량이 상당히 줄어든 모습을 제 스스로가 느낍니다. 기선님의 영상을 봤을 때는 테스트의 중요함을 한번 더 느꼈고, 다른 개발자분들도 더 나은 개발자가 되기 위해서, 본인의 코딩 퀄리티를 높이기 위해서 테스트 코드를 잘 작성하는 것에 대한 중요성을 같이 느끼고 개발해 나갔으면 좋겠습니다!

 

 

댓글

Designed by JB FACTORY