[Q&A] SpringBoot3 Test

이 글은 AI와의 질의응답 과정에서 얻은 정보를 요약하고 정리한 내용입니다.


1. WebMVCTest, SpringBootTest 차이점

Spring 테스트에서 사용되는 애너테이션인 @AutoConfigureMockMvc, @WebMvcTest, @SpringBootTest는 각각 테스트의 범위, 속도, 의존성 주입 대상 등을 다르게 설정하는 데 사용된다.


가. WebMvcTest

  • Controller 레이어만 테스트할 때 사용.
  • @Controller, @RestController, @ControllerAdvice 등 MVC 컴포넌트만 로딩.
  • Repository, Service 등은 주입되지 않음. 필요시 @MockBean으로 mocking 필요.
  • 기본적으로 MockMvc를 자동 구성해 줌.
  • 가장 빠름. 최소한의 컴포넌트만 로딩함.
@WebMvcTest(MyController.class)
class MyControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private MyService myService; // 명시적으로 mock 해야 함
}
Code language: PHP (php)

나. SpringBootTest

  • 통합 테스트 (전체 스프링 컨텍스트 로딩).
  • 전체 애플리케이션 컨텍스트 (Controller, Service, Repository 등 전부).
  • 기본적으로는 설정되어 있지 않으며, @AutoConfigureMockMvc를 함께 써야 MockMvc 사용 가능.
  • 느림. 전체 컨텍스트 로딩.
@SpringBootTest
@AutoConfigureMockMvc
class MyIntegrationTest {
    @Autowired
    private MockMvc mockMvc;
}
Code language: CSS (css)

다. AutoConfigureMockMvc

  • MockMvc를 사용할 수 있도록 설정만 해줌.
  • @SpringBootTest와 함께 사용해야 효과 있음.
  • MockMvc 객체를 자동 구성하여 주입 가능하게 함.

라. 결론

애너테이션목적로딩 범위MockMvc 자동 설정테스트 속도주의할 점
@WebMvcTest단위 테스트 (Controller)MVC 컴포넌트만O빠름Service 등은 @MockBean 필요
@SpringBootTest통합 테스트전체 애플리케이션 컨텍스트X (직접 설정 필요)느림진짜 Bean이 모두 로딩됨
@AutoConfigureMockMvcMockMvc 설정별도 의미 없음 (보조용)ON/A (보조)@SpringBootTest와 같이 사용
  • Controller만 테스트: @WebMvcTest
  • Service와 DB까지 통합해서 테스트: @SpringBootTest + @AutoConfigureMockMvc
  • 전체 흐름 테스트 (인증, 예외 처리 등 포함): @SpringBootTest + MockMvc 또는 TestRestTemplate

2. 테스트 클래스의 Transactional과 JPA 개발의 Transactional은 동일한가?

네.

테스트 클래스에 사용하는 @Transactional과 JPA 개발에 사용하는 @Transactional은 근본적으로 같은 애너테이션이다.

둘 모두 org.springframework.transaction.annotation.Transactional에서 제공되며, 스프링의 트랜잭션 관리 기능을 적용.

다만 테스트 환경에서는 그 동작 방식이 다르게 적용된다.


가. 테스트 클래스에서의 Transactional

  1. 각 테스트 메서드마다 트랜잭션이 자동 시작됩니다.
  2. 테스트가 끝나면 해당 트랜잭션은 자동으로 롤백됩니다. 즉, 테스트 중 DB에 insert/update/delete가 일어나도 테스트 끝나면 DB에 반영되지 않음.

따라서 테스트 간의 상태 오염을 막을 수 있음.

@SpringBootTest
@Transactional
class MyRepositoryTest {

    @Autowired
    private MyRepository repository;

    @Test
    void testSaveEntity() {
        repository.save(new MyEntity("hello"));
        // insert는 실행되지만, 테스트 종료 후 rollback됨
    }
}
Code language: JavaScript (javascript)

테스트에서 @Transactional을 붙었는데 왜 실제 DB에는 적용되지 않는 이유는 Spring Test의 “자동 롤백” 동작 때문.

@Transactional + @SpringBootTest의 조합은 Spring Test는 테스트가 끝난 후 자동으로 rollback()을 호출한다.

@SpringBootTest
@Transactional
class MyTest {

    @Test
    void testSave() {
        myRepository.save(...);  // INSERT 쿼리 발생
        // 여기까지는 실제로 DB에 insert 됨
    }
    // 테스트 메서드 종료 시 -> 트랜잭션 rollback
}
Code language: JavaScript (javascript)

💡실제 DB에 반영되도록 하고 싶다면?

@Commit 또는 @Rollback(false) 사용


3. WithMockUser, WithUserDetails에 대한 설명

@WithMockUser@WithUserDetails는 Spring Security 테스트용 애너테이션입니다.

두 애너테이션 모두 인증이 필요한 컨트롤러나 서비스 테스트에서 사용자 인증을 시뮬레이션하는 데 사용됩니다.

@WithMockUser는 가짜 인증 정보를 주입하고, @WithUserDetails는 실제 UserDetailsService를 통해 사용자 정보를 가져와 테스트합니다.

비교 항목@WithMockUser@WithUserDetails
작동 방식가상의 사용자 정보 생성실제 UserDetailsService 사용
DB 조회하지 않음실제 DB 조회
테스트 속도빠름상대적으로 느림
사용 케이스간단한 권한 검사실제 사용자 기반 테스트
보안 애너테이션@PreAuthorize, @Secured 지원@PreAuthorize, @Secured 지원
// WithMockUser 예제
@WithMockUser(username = "testuser", roles = {"USER"})
@Test
void testWithMockUser() {
    mockMvc.perform(get("/secured"))
           .andExpect(status().isOk());
}

// WithUserDetails 예제
@WithUserDetails("realuser") 
@Test
void testWithRealUser() {
    mockMvc.perform(get("/secured"))
           .andExpect(status().isOk());
}

// SecurityContextHolder에서 정보 읽어오기
@WithMockUser(username = "testuser", roles = "USER")
@Test
void testServiceUsesSecurityContext() {
    String username = SecurityContextHolder.getContext().getAuthentication().getName();
    assertEquals("testuser", username);
}
Code language: PHP (php)

가. 일반적인 사용 패턴

  • @WithMockUser: 주로 단위 테스트에서 사용 (예: @WebMvcTest)
  • @WithUserDetails: 주로 통합 테스트에서 사용 (예: @SpringBootTest)

이러한 패턴이 일반적인 이유:

  • 단위 테스트에서는 가벼운 모의 객체가 필요하므로 @WithMockUser가 적합
  • 통합 테스트에서는 실제 사용자 데이터와의 상호작용을 테스트해야 하므로 @WithUserDetails가 적합

단위 테스트에 사용하는 @WebMvcTest에서는 컨트롤러만 로딩된다.

이에 UserDetailservice 구현체가 등록되지 않아서 @WithUserDetails가 정상적으로 동작하지 않을 가능성이 높다.


댓글 남기기