본문 바로가기
Development/Spring

테스트 코드 작성 시 유의사항

by 메정 2021. 9. 23.

추가 예정

단위테스트 vs 통합테스트

단위테스트(Unit Test)

개발 단계에서 각 모듈이 개발완료된 시점에서 수행되는 테스트

@ExtendWith(MockitoExtension.class)를 통해 테스트 진행

개발된 각 모듈을 테스트. 즉, 하나의 기능(모듈)이 잘 동작하는지를 확인하는 과정 (==모듈 테스트)

모듈이 개발 완료되는 시점에서 개발자가 명세서 기반으로 정확히 개발했는지 테스트 진행

통합테스트(Integration Test)

모듈을 통합하는 과정에서 모듈 간 호환성의 문제를 찾아내기 위해 수행되는 테스트

@SpringBootTest를 통해 테스트 진행

모듈 간의 연결 작업이 올바르게 연계되어 작동하는지를 테스트하는 과정

  1. 빅뱅 통합 : 전체 모듈을 모두 통합한 후 통합 테스트를 수행. 오류발생 시 찾기 어려움
  2. 점진적 통합 : 점진적으로 통합하는 방식으로 상향식, 하향식 기법으로 나뉨. 오류 발생 시 빠르게 발견 가능

단위테스트 작성의 필요성

  1. 테스팅에 대한 시간과 비용 절감 가능
    1. 통합테스트 진행 시 DB 연결 등 시스템을 구성하는 컴포넌트들간의 연결이 필요하여 시간 비용이 커짐
    2. 단위테스트를 진행하면, 해당 기능(모듈)만 테스팅하므로 시간 단축 가능
  2. 새로운 기능 추가 시 수시로 빠르게 테스팅 가능
  3. 리팩토링 시 안전성 확보 가능
    1. 기능(모듈)에 대하여 독립적으로 테스팅하므로 어떤 코드를 리팩토링하여도 빠르게 문제여부 확인 가능
  4. 코드에 대한 문서가 될 수 있음

//TDD(Test-Driven Development, 테스트 주도 개발)에서 얘기하는 테스트는 단위테스트를 의미

//개발한 것에 대해 빠르게 검증 받는 것이 단위테스트의 장점

대부분의 테스트코드유닛 테스트코드로 작성하는것을 원칙으로 하고, 컴포넌트간의 전체 프로세스를 테스트할 때만 통합테스트를 작성한다!

단위테스트의 문제점과 Stub

MVC 패턴으로 개발된다면, 1개의 기능을 처리하기 위해(ex. 공연 정보 조회) 다른 객체들과 메세지를 주고 받아야 함.(ex. Service 객체 ↔ Repository 객체)

이렇게 되면, 모듈에 대한 독립적인 테스트를 진행할 수 없으므로 가짜 객체(Mock Object)를 주입하여 어떤 결과를 반환할 수 있도록 준비시켜줘야 함. 이 가짜 객체를 Stub.

ex. DB에 새로운 데이터를 추가하는 코드를 테스트

가짜 데이터베이스(Mock Database)를 주입시켜 insert 처리 시 반드시 1을 반환하도록 해주는 것이 Stub

좋은 단위테스트의 특징

테스트 코드 작성 시 유의사항

  1. 1개의 테스트 함수는 1개의 개념만을 테스트
    • ex. 중복으로 등록을 실패하는 경우, 성공하는 경우일 때 → 2개의 테스트 메소드로 작성
  2. 1개의 테스트 함수에 대해 Assert를 최소화
  3. 테스트 함수 작성 시 test 메서드 명을 구체적으로 표시할 것!
    • @DisplayName 을 이용하여 테스트 케이스를 구체적으로 표시

@DisplayName

테스트 메소드명이 길어져 한눈에 보기 어려울 경우, @DisplayName 어노테이션을 사용하여 어떤 테스트인지 상황을 구체적으로 표시하는데 확인하기 좋음

FIRST 규칙

  • Fast : 빠르게 동작하여 자주 돌릴 수 있도록 한다.
  • Independent : 각각의 테스트는 독립적이며 서로 의존해서는 안된다.
  • Repeatable : 어느 환경에서도 반복 가능해야 한다.
  • Self-Validating : 테스트는 성공 or 실패로 bool 값으로 결과를 내어 자체적으로 검증되도록 한다.
  • Timely : 테스트하려는 실제 코드를 구현하기 직전에 구현해야 한다.

Given/When/Then 패턴

given-when-then 패턴으로 작성하면 테스트 내 각 단계가 어떤 것인지 파악하기 쉬움

  • given 데이터 준비
  • when 테스트 실행(함수 실행)
  • then 테스트 결과 검증

아래 예시는 통합테스트로 구현된 코드!

given, when, then과 assertThat에 대한 쉬운 설명을 위해 추가한 예제 코드!

@Test
@DisplayName("[성공] 날짜를 정확하게 입력한 경우")
    void 공연_날짜_정보_조회() {
                //given
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date startDate = format.parse("2020-06-20");

                //when
        List<PerformanceResponse> result = performanceRepository.findByStartDateGreaterThanEqualOrderByStartDateAsc(startDate);

                //then
        assertThat(result.size()).isNotZero();
    }

then의 검증은 성공 or 실패로 bool 값으로 결과를 내어 검증하도록 구현하기 위해 assertThat()의 결과가 isFalse(), isTrue(), isNull(), isNotNull(), isNotZero() 등의 메소드로 구현

실패테스트를 구현하여 예외를 발생해야할 경우

@Test
@DisplayName("[실패] NOT FOUND ERROR")
void 공연_날짜_정보_조회실패() throws ParseException {
    //given
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date startDate = format.parse("2021-06-31");

    //when
    final NotFoundException exception = assertThrows(NotFoundException.class, () -> performanceRepository.findByStartDateGreaterThanEqualOrderByStartDateAsc(startDate));

    //then
        assertThat(exception.getMessage()).isNotNull();
}

when 부분에서 assertThrows()를 호출하도록 구현할 수 있음

참고

댓글