JUnit5와 Spring Test 기초: 단위 테스트부터 통합 테스트까지

Spring Boot로 개발을 하다 보면, 테스트는 선택이 아닌 필수입니다.
JUnit5의 핵심 개념과 함께, Spring Test에서 어떻게 활용하는지에 대해 설명합니다.

 


1. JUnit5란 무엇인가?

JUnit5는 자바 진영에서 가장 널리 사용되는 테스트 프레임워크인 JUnit의 최신 버전입니다.
JUnit4에서 구조적으로 개선된 점이 많고, 다양한 확장 기능이 포함되어 있어 Spring 환경에서도 유연하게 사용할 수 있습니다.

주요 구성 요소

  • JUnit Platform: 테스트 실행 엔진
  • JUnit Jupiter: JUnit5의 API와 테스트 어노테이션 제공
  • JUnit Vintage: JUnit3, JUnit4 백워드 호환

 


2. JUnit5 기본 어노테이션


@Test           // 테스트 메서드
@BeforeEach     // 각 테스트 실행 전 실행
@AfterEach      // 각 테스트 실행 후 실행
@BeforeAll      // 전체 테스트 시작 전 1회 실행 (static)
@AfterAll       // 전체 테스트 종료 후 1회 실행 (static)
@DisplayName    // 테스트 설명

예시:


class CalculatorTest {

    private Calculator calculator;

    @BeforeEach
    void setUp() {
        calculator = new Calculator();
    }

    @Test
    @DisplayName("덧셈 연산 테스트")
    void testAdd() {
        assertEquals(5, calculator.add(2, 3));
    }
}

 

 


3. Spring Boot와 통합 테스트

Spring Boot에서는 단순한 단위 테스트 외에, 빈 생성부터 DI까지 포함한 통합 테스트도 가능해야 합니다.
이를 위해 사용하는 어노테이션이 @SpringBootTest입니다.

예시


@SpringBootTest
class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    void getUserTest() {
        User user = userService.getUserById(1L);
        assertNotNull(user);
    }
}

동작 방식

  • Spring Boot 애플리케이션 전체 컨텍스트 로딩
  • 테스트 중 DI, 트랜잭션, 프로파일 등 실제 운영환경과 유사한 환경 제공
  • 기본적으로 test 프로파일이 사용됨

 


4. @WebMvcTest와 슬라이스 테스트

모든 빈을 로딩하지 않고 특정 계층만 테스트할 수도 있습니다.
대표적으로 컨트롤러 레이어만 테스트하고 싶을 때 @WebMvcTest를 사용합니다.


@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    void getUserTest() throws Exception {
        given(userService.getUserById(1L)).willReturn(new User(1L, "홍길동"));

        mockMvc.perform(get("/users/1"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.name").value("홍길동"));
    }
}

@MockBean을 사용하면 실제 빈 대신 모킹 객체를 주입할 수 있습니다.

 

 


5. 테스트에서 트랜잭션 처리

@Transactional을 테스트 클래스나 메서드에 붙이면 각 테스트가 완료된 후 자동 롤백됩니다.


@SpringBootTest
@Transactional
class UserRepositoryTest {
    ...
}

이를 통해 테스트 후 DB에 데이터가 남지 않아 테스트 간 영향이 없습니다.

 

 


6. TestEntityManager 활용

JPA 관련 테스트에서는 TestEntityManager를 활용하면 더 정교한 검증이 가능합니다.


@DataJpaTest
class UserRepositoryTest {

    @Autowired
    private TestEntityManager em;

    @Autowired
    private UserRepository userRepository;

    @Test
    void findByNameTest() {
        User user = new User("김철수");
        em.persist(user);
        em.flush();

        Optional<User> found = userRepository.findByName("김철수");
        assertTrue(found.isPresent());
    }
}

 

 


결론

단위 테스트는 빠른 피드백 루프를 제공하고, 통합 테스트는 시스템 전반의 신뢰성을 검증합니다.
Spring Boot에서는 JUnit5와 다양한 테스트 어노테이션을 통해 계층별로 필요한 테스트를 유연하게 작성할 수 있습니다.

테스트는 시간이 드는 일이지만, 장기적으로는 개발 생산성과 안정성을 모두 높이는 투자입니다.