개발/부트캠프

본캠프 : 테스트 코드

EJ EJ 2025. 2. 26. 09:58

테스트 준비

  • Spring Boot
dependencies {
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

 📌 스프링 부트에서는 이미 호환되는 버전의 테스트 관련 라이브러리들이 제공된다.

  • 테스트는 중요하기에 따로 테스트 관련 의존성을 넣지 않더라도 default로 포함되어있다.

 

Given-When-Then 패턴

Given : 주어진 전제 조건을 정의하고 테스트 실행을 위한 준비 "어떤 배경이나 상태가 주어졌을 때"

When : 테스트하려는 메서드나 기능을 실행하는 과정 "어떤 행동을 실행하면"

Then : 메서드나 기능이 실행된 후 예상되는 결과가 나오는지 확인 "예상한 결과가 맞는지 확인한다"

 

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class BasicTest {
    @Test
    @DisplayName("더하기 테스트")
    public void calTest() {
        // given
        int a = 1;
        int b = 3;

        // when
        int sum = a + b;

        // then
        assertEquals(4, sum);
    }
}

(결과에 대한 확인은 단언문 Assertions 사용)

 

스프링 테스트

Annotation 종류

1. @DataJpaTest

  • JPA와 관련된 Component들만 모두 가지고와 Repository Layer 단위 테스트를 위한 Annotation이다.
  • 기본적으로 In-memory DB(ex H2)를 사용하여 테스트한다.

요약: JPA 레포지토리 단위 테스트

 

2. @ExtendWith

  • Junit5 환경에서 확장기능을 사용할때 사용한다.
  • 주로 MockitoExtension 과 함께 Service Layer, 클래스 단위 테스트에 사용한다.

요약: 서비스 단위 테스트(+@Component)

 

3. @WebMvcTest

  • 스프링의 Web Layer(controller, filter 등)을 테스트하기 위한 Annotation이다.
  • @Controller, @ControllerAdvice 등 웹과 관련된 Bean만 로드하여 테스트를 수행한다.

요약: 컨트롤러 단위 테스트

 

4. @SpringBootTest

  • 스프링 부트 전체를 테스트 수행하기 위해서 사용하는 Annotation이다.
  • 서버를 실행하듯 모든 스프링 Context를 로드한다.

요약: 통합 테스트

 

Mocking

테스트 코드를 작성하면 테스트를 하기 위한 코드 이외의 의존 객체들이 존재하는 경우가 있다. 예를 들면 Service 코드를 테스트 하는데 Repository가 필요한 경우이다.

  • 사용 이유
  1. 외부 의존성 제거
  2. 테스트 범위 준수
  3. 에러 상황 강제 발생

 

행위 검증(Behavior Validation), 상태 검증(State Validation)

  • 행위 검증
    • **“테스트시 특정한 행위를 하였는가”**를 확인하는 행위이다.
    • 테스트를 하려는 코드가 어떤 메소드를 호출하였는지 하지 않았는지, 몇번 수행했는지 확인.
    • Mockito의 verify() 메소드를 통해 검증
  • 상태 검증
    • **“기능 수행 후 결과값이 기대값과 일치하는가?”**를 확인하는 행위이다.
    • 반환값, DB 저장된 데이터 등 에 대해 의도한대로 반환/저장이 되는지 확인.
  • application-test.properties
spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL;
spring.datasource.username=root
spring.datasource.driver-class-name=org.h2.Driver

spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database=h2

(default로 테스트 코드는 H2를 사용)

 

 

[ 테스트 코드 실습 ] 

▶ Repository → Service → Controller 순서로 테스트 코드 작성!

하는 것이 기본이지만, Repository 같은 경우는 과거에 비해 쿼리를 간단하게 가져가는 추세이기 때문에 그렇게 복잡한 로직이 잘 없다. 복잡한 로직이 없으므로 예외 경우의 수가 거의 없다. 따라서 중요도가 떨어진다 판단하여 우선순위에서 밀리는 경우도 있다.

특히, JPA의 단순 save(), findAll(), findById() 같은 메서드들은 이미 라이브러리에서 검증이 끝난 메서드이므로 테스트를 하는 것이 크게 의미 없을 수 있다.

 

▶ 단축키 : command N

클래스명에 커서를 두고 단축키 콤맨드 N을 누르고 Test 클릭, Test 클래스 자동 생성됨

 

▶ 진행 방식

1.Repository 테스트

@DataJpaTest : 전체

@Autowired : Spring에서 의존성 주입(Dependency Injection, DI)을 자동으로 처리하는 어노테이션

@Test

 

2.Service 테스트

@ExtendWith(MockitoExtension.class) : 전체

@Mock : 테스트 대상 외의 의존 객체(모두 작성)

@InjectMocks : 테스트 대상 객체

@Test

 

3.Controller 테스트

@WebMvcTest(XxxController.class) : 전체

@Autowired

@MockBean : 테스트 대상 외의 의존 객체(모두 작성)

@Test

 

자금 진행하는 과제 프로젝트는 3.3.x버전이기에 @MockBean과 MockMvc를 활용한다.

실무에서도 아직 3.4를 도입한 회사가 없을 것이기에,  취업을 해도 한동안은 @MockitoBean과 MockMvcTester를 사용할 일은 아직 없을 것으로 생각된다.