JUnit5 단위 테스트 코드 작성

dragonappear·2022년 2월 21일
0

TDD

목록 보기
2/5


출처

제목: [Java] JUnit을 활용한 Java 단위 테스트 코드 작성법 (2/3)
작성자: tistory"망나니개발자"
작성자 수정일: 2021년 04월 20일
링크: https://mangkyu.tistory.com/144
작성일: 2022년 2월 21일


1. Java 단위 테스트(Unit Test) 작성 준비

필요한 라이브러리

요즘 Java 단위 테스트 작성에는 크게 2가지 라이브러리가 사용된다.

  • JUnit5: 자바 단위 테스트를 위한 테스팅 프레임워크
  • AssertJ: 자바 테스트를 돕기 위해 다양한 문법을 지원하는 라이브러리

JUnit 만으로도 단위 테스트를 충분히 작성할 수 있지만, JUnit에서 제공하는 assertEquals()와 같은 메서더는 AssertJ가 주는 메서드에 비해 가독성이 떨어진다. 그렇기 때문에 순수 Java 어플리케이션에서 단위 테스트를 위해 JUnit5와 AssertJ 조합이 많이 사용된다.

given/when/then 패턴

given-when-then 패틴어리나 1개의 단위테스트를 3가지 단계로 나누어 처리하는 패턴으로, 각각의 단계는 다음을 의미한다.

  • given(준비): 어떠한 데이터가 준비되었을 때
  • when(실행): 어떠한 함수를 실행하면
  • then(검증): 어떠한 결과가 나와야 한다.

추가적으로 어떤 메서드가 몇번 호출되었는지를 검사하기 위한 verify 단계도 사용하는 경우가 있는데, 그렇게 실용성이 크지 않으므로 메서드의 호출 횟수가 중요한 테스트에서만 선택적으로 사용하면 될 것 같다.

테스트 코드 작성 공통 규칙

@DisplayName("로또 번호 갯수 테스트") 
@Test 
void lottoNumberSizeTest() {    
// given    
// when    
// then 
}
  • @Test
    • 해당 메서드가 단위 테스트임을 명시하는 어노테이션이다.
    • JUnit은 테스트 패키지 하위의 @Test 어노테이션이 붙은 메서드를 단위 테스트로 인식하여 실행시킨다.
    • 이 상태로 실행하면 테스트 이름이 함수 이름이 default로 지정되는데, @DisplayName 어노테이션을 사용하여 읽기 좋은 다른 이름을 부여할 수 있다.

또한 테스트 코드는 앞서 설명한 given-when-then 패턴으로 흔히 작성되는데, 단위 테스트 내에 주석으로 이 단계를 명시해주면 읽기 좋은 테스트 코드를 작성할 수 있다.


2. 단위 테스트 작성 예시

로또 생성기 Java 코드

예를 들어 다음과 같이 1000원을 주면 1개의 로또를 생성해주는 클래스가 있다고 하자.

public class LottoNumberGenerator {

    public List<Integer> generate(int money) {

        if (!isValidMoney(money)) {
            throw new RuntimeException("올바른 금액이 아닙니다");
        }
        return generate();
    }

    private boolean isValidMoney(int money) {
        return money == 1000;
    }

    private List<Integer> generate() {
        return new Random()
                .ints(1, 45 + 1)
                .distinct()
                .limit(6)
                .boxed()
                .collect(Collectors.toList());
    }
}

위와 같은 로또 번호 생성 코드에 대한 테스트 코드듣ㄹ을 작성해보자
1. 로또 번호 갯수 테스트
2. 로또 번호 범위 테스트
3. 잘못된 로또 금액 테스트

1. 로또 번호 갯수 테스트

우선 로또를 생성받기 위해서는 로또 생성기 객체와 금액이 필요하다.

그렇기에 given 단계에서는 LottoNumberGenerator 객체와 금액을 적어주면 된다.

@DisplayName("로또 번호 갯수 테스트")
@Test
    void lottoNumberSizeTest(){
        //given
        LottoNumberGenerator generator = new LottoNumberGenerator();
        int price = 1_000;
        //when

        //then
    }

준비가 끝났으면 주어진 금액을 지불하여 로또를 받아야 한다.
이에 대한 when 단계의 코드를 작성하면 다음과 갘다.

@DisplayName("로또 번호 갯수 테스트")
    @Test
    void lottoNumberSizeTest(){
        //given
        LottoNumberGenerator generator = new LottoNumberGenerator();
        int price = 1_000;
        //when
        List<Integer> list = generator.generate(price);
        //then
    }

이제 최종적으로 우리가 받은 로또가 6개의 숫자를 갖는지 검증해야 한다.
이에 대한 테스트 코드를 작성하면 다음과 같다.

@DisplayName("로또 번호 갯수 테스트")
    @Test
    void lottoNumberSizeTest(){
        //given
        LottoNumberGenerator generator = new LottoNumberGenerator();
        int price = 1_000;
        //when
        List<Integer> list = generator.generate(price);
        //then
        Assertions.assertThat(list.size()).isEqualTo(6);
    }

2. 로또 번호 범위 테스트

@DisplayName("로또 번호 범위 테스트")
    @Test
    void lottoNumberRangeTest(){
        //given
        LottoNumberGenerator generator = new LottoNumberGenerator();
        int price = 1_000;
        //when
        List<Integer> list = generator.generate(price);
        //then
        Assertions.assertThat(list.stream().allMatch(n -> n >= 1 && n <= 45)).isTrue();
    }

이번에는 모든 로또 숫자가 1에서 45사이의 숫자인지를 boolean 값으로 검사하므로, AssertJisTrue() 문법이 사용되었다. 그 외에도 isFalse(), isNull(), isNotNull() 등의 메소드가 있다.

3. 잘못된 로또 금액 테스트

  • 마지막으로 잘못된 금액이 발생한 경우, Runtime Exception이 발생하는 코드에 대해 테스트를 해야 한다.
  • 예외가 발생하는 경우에는 when 단계에서 junitassertThrows()로 감싸서 처리를 해야 한다.
@DisplayName("잘못된 로또 금액 테스트")
    @Test
    void lottoNumberInvalidMoneyTest(){
        //given
        LottoNumberGenerator generator = new LottoNumberGenerator();
        int price = 2_000;
        //when
        RuntimeException ex = assertThrows(RuntimeException.class, () -> generator.generate(price));
        //then
        Assertions.assertThat(ex.getMessage()).isEqualTo("올바른 금액이 아닙니다");
    }

간단한 자바 어플리케이션이라서 어떤 메서드가 다른 객체와 메시지를 주고 받을 필요가 없는 경우라면 단위 테스트 작성이 간단하다. 하지만 일반적인 어플리케이션은 상당히 복잡하고, 여러 객체들이 메시지를 주고 받는다. 그렇기 때문에 Spring과 같은 웹 어플리케이션에서는 어떻게 단위 테스트를 작성하는지에 대해 알아볼 필요가 있다.

1개의 댓글

comment-user-thumbnail
2022년 11월 12일

감사합니다 덕분에 JUnit5 테스트 많이 배우고 갑니다.

답글 달기