Spring Test - @WebMvcTest

목차

@WebMvcTest

Spring MVC 를 테스트하기 위해 사용되는 어노테이션, MVC 테스트와 관련된 Configuration 이 적용된다.

  • @Controller, @ControllerAdvice, @JsonComponent, Converter/GenericConverter, Filter, HandlerMethodArgumentResolver, WebMvcConfigurer 를 Scan 한다.
  • @Component, @Service, @Repository Bean은 적용되지 않는다.
  • MVC 테스트시 Spring Security 설정도 자동적으로 추가해준다.
  • controllers 속성을 이용해 특정 Controller 를 지정함으로써 해당 Controller 만 테스트 진행할 수 있다.
  • includeFilters 속성과 excludeFilters 속성을 이용해 특정 Filter 를 추가하거나 제외할 수 있다.

장점

  • @SpringBootTest 에 비해 MVC 에 필요한 구성만 불러옴으로 훨씬 가볍고 빠르다.

단점

  • Mock 기반 테스트를 진행하기 때문에 운영에서는 제대로 동작하지 않을 수 있다.

@WebMvcTest 를 이용한 Test 코드

@WebMvcTest(
value = PostController.class
, excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JsonSecurityConfig.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtSecurityConfig.class)}
)
@ActiveProfiles("local")
class PostControllerTest {

@MockBean
private JwtUtils jwtUtils;

@Autowired
private MockMvc mockMvc;

@MockBean
private PostService postService;

@MockBean
private CategoryService categoryService;

@Autowired
private ObjectMapper objectMapper;

@MockBean(name = "userDetailsService")
private UserInfoUserDetailsService userInfoUserDetailsService;

@PostConstruct
public void setup() {
given(userInfoUserDetailsService.loadUserByUsername(anyString()))
.willReturn(new User("test", "password", AuthorityUtils.createAuthorityList("ROLE_WRITE")));
}

@Test
@WithMockUser
void getAllTest() throws Exception {
List<Page> posts = new ArrayList<>();
given(postService.getAllPosts(PageRequest.of(0, 3))).willReturn(new PageImpl(posts));

ResultActions resultActions = mockMvc.perform(get("/api/post"));

resultActions
.andExpect(status().isOk());
}

@Test
@WithUserDetails
void saveTest() throws Exception {
String title = new String("Title");
String subTitle = new String("subTitle");
String content = new String("content");
String beforeCategoryName = new String("beforeCategory");
String afterCategoryName = new String("afterCategory");

RequestPostDto requestPostDto = new RequestPostDto();
requestPostDto.setTitle(title);
requestPostDto.setSubTitle(subTitle);
requestPostDto.setContent(content);
requestPostDto.setCategory(afterCategoryName);

Category beforeCategory = Category.builder()
.name(beforeCategoryName)
.posts(new ArrayList<>())
.build();

Category afterCategory = Category.builder()
.name(afterCategoryName)
.posts(new ArrayList<>())
.build();

Post post = Post.builder()
.id(1L)
.title(title)
.subTitle(subTitle)
.content(content)
.category(beforeCategory)
.build();

given(categoryService.saveOrFindCategory(afterCategoryName)).willReturn(afterCategory);
given(postService.savePost(any(Post.class))).willReturn(post);

String requestBody = objectMapper.writeValueAsString(requestPostDto);

ResultActions resultActions = mockMvc.perform(post("/api/post/new")
.with(csrf())
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
);

resultActions
.andExpect(status().isCreated())
.andDo(print());

verify(postService).savePost(any(Post.class));
}

@Test
@WithUserDetails
void saveFailTest() throws Exception {
String title = new String("Title");
String subTitle = new String("subTitle");
String content = new String("content");
String afterCategoryName = new String("afterCategory");

RequestPostDto requestPostDto = new RequestPostDto();
requestPostDto.setTitle(title);
requestPostDto.setSubTitle(subTitle);
requestPostDto.setContent(content);
requestPostDto.setCategory(afterCategoryName);

Category afterCategory = Category.builder()
.name(afterCategoryName)
.posts(new ArrayList<>())
.build();


given(categoryService.saveOrFindCategory(afterCategoryName)).willReturn(afterCategory);
given(postService.savePost(any(Post.class))).willThrow(PostSaveFailException.class);

String requestBody = objectMapper.writeValueAsString(requestPostDto);

ResultActions resultActions = mockMvc.perform(post("/api/post/new")
.content(requestBody)
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
);

resultActions
.andExpect(status().isBadRequest())
.andDo(print());

verify(postService).savePost(any(Post.class));
}

@Test
@WithUserDetails
void deletePostTest() throws Exception {
Long id = 1L;

ResultActions resultActions = mockMvc.perform(delete("/api/post/delete/" + id)
.with(csrf()));

resultActions
.andExpect(status().isOk())
.andDo(print());

verify(postService).deletePost(1L);
}
}
Share