JAVA & Spring/Java Library

[JUnit] 테스트 코드 작성과 단위테스트 Unit Test

HSRyuuu 2023. 10. 5. 00:19

JUnit


  • Java용 유닛 테스트 프레임워크이다.
  • 소프트웨어 개발 시에 단위테스트(Unit Testing)는 중요한 절차이다.
  • 프로그램을 작은 unit 단위로 쪼개어 각각 잘 동작하는지 검사함으로써 프로그램의 안정성을 높인다.

1) 테스트 주도 개발 (TDD)

테스트 주도 개발(Test-Driven Development)란, 테스트 케이스를 작성하고 소스코드가 이를 통과하는지 반복하여 확인하며 개발하는 것을 말한다. TDD는 기능의 구현 목표에 집중하여 개발 생산성을 높이고, 이후 리팩토링과 유지보수에 이점을 가져다준다.

테스트코드를 처음 접했을 때, 사소하고 틀일일이 없다고 생각하는 부분까지 테스트를 하는 것을 보고 놀랐다.

2) 단위 테스트(Unit Testing)

각 작은 단위가 구현 목표에 맞게 잘 동작하는지 확인하는 것이다.
자바에서는 보통 메서드마다 구현 목표에 맞게 잘 동작하는지 확인하는 것이 중요하다.

 

given / when / then 패턴


given - when - then 패턴을 이용하여 작성한다.

  • given : 테스트에서 구체화하고자 하는 행동을 하기 전 테스트의 상태를 설명하는 부분
  • when : 구체화하고자 하는 행동
  • then : 예상되는 변화를 확인, 검증
    @Test
    void method1() {
        //given ( 멤버 생성 )이 주어졌을 때
        Member member = new Member(1L,"memberA",Grade.VIP);
        //when  ( 멤버를 회원가입 시킨 뒤, 멤버를 조회) 했을 때
        memberService.join(member);
        Member findMember = memberService.findMember(1L);
        //then   ( 아래 조건을 만족해야 한다. )
        Assertions.assertThat(member).isEqualTo(findMember);
    }

 

FIRST :  좋은 테스트를 작성하는 5가지 속성


Fast : 빠르게

테스트는 빠르게 수행되어야 한다. 테스트가 느리면 코드를 개선하는 작업이느려져 코드 품질이 떨어질 수 있다.

목적을 단순하게 설정해서 작성하거나, 외부 환경을 사용하지 않는 단위 테스트를 작성하면 좋다.

Isolated : 고립된, 독립적

하나의 테스트코드는 하나의 대상에 대해서만 수행되어야 한다. 만약 하나의 테스트가 다른 테스트 코드와 상호작용하거나 관리할 수 없는 외부 소스를 사용하게 되면 이후 외부 요인으로 인해 테스트케이스가 실패할 수도 있다.

Repeatable : 반복 가능한

테스트는 어떤 환경에서도 반복 가능하도록 작성해야 한다.

Self-Validating : 자가 검증

테스트는 그 자체만으로 테스트의 검증이 완료되어야한다.  assert 메서드 등을 통해 테스트가 성공했는지 실패했는지 확인할 수 있는 코드를 작성해야 한다. 만약 개발자가 테스트 코드 작성 후 눈으로 확인해야한다면 좋지 못한 테스트코드이다.     

Timely : 적시에

테스트코드는 테스트하려는 애플리케이션 코드를 구현하기 전에 완성되어야 한다. 너무 늦게 작성된 테스트코드는 정상적인 역할을 수행하지 못할 수 있다. 또한 테스트 코드로 인해 발견된 문제를 해결하기 위해 소모되는 개발 비용이 커질 수 있다. 즉 미리미리 테스트코드를 짜야한다. 다만 이 개념은 TDD(테스트 주도 개발)시에만 중요하고, 이외에는 이 규칙은 생략하고 진행할 수도 있다.

 

Assertions 클래스


예제에서 사용된 Assertions는 org.assertj.core.api.Assertions이다.

    • Assertions 클래스를 static import 하면 'Assertions' 생략 가능

Assertions.assertThat()... -> assertThat()...

 

(예제)

import org.assertj.core.api.Assertions;

Assertions.assertThat(findMember).isEqualTo(savedMember);

Assertions.assertThat(List list).contains("hello","world");

Methods

1) isEqualTo

assertThat(Object obj1).isEqualTo(Object obj2);
  • obj1과 obj2가 같으면, 테스트 통과

2) contains

assertThat(List list).contains(obj1,obj2);
  • list에 obj1, obj2가 포함되어 있으면 통과

3) containsExactly

assertThat(String[] arr).containsExactly(str1, str2, str3);
  • 배열 arr에 str1, str2, str3가 모두 존재해야지만 통과

4) assertThatThrownBy

assertThatThrownBy( () -> logic()).isInstanceOf(IllegalStateException.class);
  • logic()을 실행했을 때 IllegalStateException오류가 발생 시 통과

Annotations

@Test

@Test는 해당 메서드가 단위 테스트임을 명시하는 어노테이션이다. JUnit은 테스트 패키지 하위의 @Test 어노테이션이 붙은 메서드를 단위 테스트로 인식하여 실행시킨다.

@DisplayName("...")

이 어노테이션 없이 실행하면 테스트 이름이 함수 이름이 default로 지정되는데,
@DisplayName 어노테이션을 사용하면 읽기 좋은 다른 이름을 부여할 수 있다.

  • 테스트 시에는 한글을 사용해도 괜찮다.

@BeforeEach , AfterEach

각 테스트 코드가 시작할 때, 끝날 때마다 동작하는 메서드

  • 아래 예제에서는 테스트가 끝날 때마다 repository를 초기화하기 위한 용도
  • 테스트 클래스 내부에 작성하면, 해당 테스트클래스 내의 메서드 실행 시마다 동작한다.
    @AfterEach
    void afterEach(){
        memberRepository.clearStore();
    }
반응형