이 글은 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이 모두 로딩됨 |
| @AutoConfigureMockMvc | MockMvc 설정 | 별도 의미 없음 (보조용) | O | N/A (보조) | @SpringBootTest와 같이 사용 |
- Controller만 테스트:
@WebMvcTest - Service와 DB까지 통합해서 테스트:
@SpringBootTest+@AutoConfigureMockMvc - 전체 흐름 테스트 (인증, 예외 처리 등 포함):
@SpringBootTest+MockMvc또는TestRestTemplate
2. 테스트 클래스의 Transactional과 JPA 개발의 Transactional은 동일한가?
네.
테스트 클래스에 사용하는 @Transactional과 JPA 개발에 사용하는 @Transactional은 근본적으로 같은 애너테이션이다.
둘 모두 org.springframework.transaction.annotation.Transactional에서 제공되며, 스프링의 트랜잭션 관리 기능을 적용.
다만 테스트 환경에서는 그 동작 방식이 다르게 적용된다.
가. 테스트 클래스에서의 Transactional
- 각 테스트 메서드마다 트랜잭션이 자동 시작됩니다.
- 테스트가 끝나면 해당 트랜잭션은 자동으로 롤백됩니다. 즉, 테스트 중 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가 정상적으로 동작하지 않을 가능성이 높다.