[Spring] 테스트의 종류, 스프링 테스트 프레임워크

테스트의 종류, 스프링 테스트 프레임워크

스파르타 코딩 클럽의 Spring 심화반 3주 차 내용인 테스트의 종류, 스프링 테스트 프레임워크을 정리한다.

핵심 내용

  • 테스트의 종류
  • 스프링 테스트 프레임워크 이해 & 사용

테스트의 종류 & 필요성

  • 블랙박스 테스트 : 내부의 구조 및 동작 원리를 모르는 블랙박스와 같은 상태(서비스의 사용자 입장)에서 동작을 검사하는 테스트 방법
    • 장점 : 누구나 테스트 가능
    • 단점 : 기능이 추가될수록 테스트의 범위가 늘어나고 테스트하는 사람이 늘어나야 한다.
  • 개발자 테스트 : 개발자가 작성한 코드를 검증해 주는 테스트 코드를 직접 작성하는 방법
    • 장점 : 빠르고 정확한 테스트, 자동화 가능, 기존 코드가 잘 동작하는지 확인할 수 있음, 배포 시에 항상 검증이 가능하다.
    • 단점 : 개발 시간이 오래 걸리고, 테스트 코드의 유지 보수 비용이 든다.
    • 스프링에선 JUnit을 이용한 단위 테스트, 통합 테스트가 있다.

스프링 테스트 프레임워크 이해 & 사용

단위 테스트

  • 프로그램을 작은 단위(클래스, 모듈, 메서드 등..)으로 쪼개서 각 단위가 정확히 동작하는지 검사하는 테스트

  • 스프링에선 자바 프로그래밍 언어용 단위 테스트 프레임워크인 JUnit을 사용하여 단위 테스트를 실행한다.

  • 테스트를 원하는 클래스, 메소드를 위한 파일을 만든 후, 테스트할 메소드에 @Test, @DisplayName("...") 등의 어노테이션을 붙인다.

  • 위의 어노테이션이 붙여져 있는 메소드에 Run '해당 메소드()'의 기능을 실행하면 테스트가 실행된다.

  • 테스트 코드는 보통 given(주어진 상황), when(테스트를 위한 실행), then(결과)로 나눠서 작성한다.

  • 결괏값은 assertNull, assertEquals, assertFalse등의 메소드에 파라미터를 넣어 확인한다.

  • 예외 처리의 경우엔 다음과 같이 확인한다.

    // 예외처리 example
    
    // when
    Exception exception = assertThrows(IllegalArgumentException.class, () -> {
                            new Product(requestDto, userId);
                        });
    // then
    assertEquals("상품 최저가가 0 이하입니다.", exception.getMessage());                      
    
  • @Nested : 클래스 안에 클래스를 넣을 수 있게 해주는 어노테이션으로 테스트 코드 결과를 확인할 때 하위 구조로 표시된다.

TDD(Test-Driven Development)

기존의 순서인

설계 -> 개발 -> 테스트 (-> 설계 수정)

의 순서를

설계 -> 테스트 (->설계 수정) -> 개발

로 변경하여 개발하는 방법

즉, 개발을 먼저하기 전에 테스트 코드를 만든 후 테스트 코드를 통과할 수 있도록 개발하는 방식이다.

Mock object (가짜 객체)

단위 테스트에서 각 테스트 케이스는 서로 분리되는 것이 이상적이기 때문에 가짜 객체를 생성하여 사용한다.

  • 동일한 클래스명과 메소드명 사용
  • Mock 객체의 내부 로직은 중요하지 않다.
  • 개발자가 Mock object 함수를 테스트 시나리오 별로 설정이 가능하다.

Mockito mock을 이용한 단위 테스트

개발자가 일일이 Mock object를 구현할 수 없기 때문에 Mockito를 사용하여 단위 테스트를 만들고 함수를 테스트 시나리오 별로 설정한다.

예시
  • @Mock 어노테이션을 붙여 해당 객체가 Mock object 임을 명시한다.

  • when, thenReturn 메소드를 활용해 시나리오를 설정한다.

    • 목 오브젝트의 정의 : 사용자의 행위를 조건부로 사전에 입력해두면, 그 상황에 예정된 행위를 수행하는 객체
      @ExtendWith(MockitoExtension.class)
      class ProductServiceTest {
          @Mock
          ProductRepository productRepository;
    
          // 생략 ...
    
          when(productRepository.findById(productId))
            .thenReturn(Optional.of(product));
      }
    

통합 테스트

  • 모듈 간에 상호 작용 검증을 못하는 단위 테스트의 한계를 극복하기 위해 통합 테스트를 실행
  • 두 개 이상의 모듈이 연결된 상태에서 테스트하며, 모듈 간의 연결에서 발생하는 에러를 검증한다.
    • ex) Controller -> Service -> Repository가 연결된 하나의 통합된 테스트를 수행
  • @SpringBootTest : 스프링 부트가 제공하는 테스트 어노테이션으로, 스프링 IoC, DB CRUD를 사용하기 위해선 선언해줘야 한다.
  • @Order(N) : 파라미터 안에 숫자를 넣어 테스트의 순서를 정할 수 있는 어노테이션