JUnit, TDD , 클린코드 연습

MockMvc 테스트

쭈녁 2024. 4. 7. 17:13

 

MockMVC를 통한 Springboot 통합 테스트를 작성해 보았다.

 

테스트 환경 세팅

// 부트가 실행될때와 같이 componentScan을 해와서 bean 세팅
@SpringBootTest
// Mock 객체의 자동 bean 주입을 해주는 어노테이션
@AutoConfigureMockMvc
class ArticleControllerTest {
    @Autowired
    MockMvc mockMvc;
    
    @Autowired
    private ObjectMapper mapper;
    @Autowired
    private WebApplicationContext context;

    @Autowired
    private ArticleRepository repository;

    //MockMvc 객체의 서블릿과 컨트롤러를 재정의 하고싶으면 아래와 같이 builder 로 재정의 가능하다.
    @BeforeEach
    void mockSetUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }
}

    @AfterEach
    void clean() {
        repository.deleteAll();
    }

 

MockMvc의 내부에는 testDispatcherServlet이 필드로 존재한다. 이는 @AutoConfigureMockMvc를 통해 의존성이 주입되지만 MockMvcBuilders를 통해 특정 환경으로 재정의도 가능하다.

 

Servlet의 정의뿐 아니라 Controller 단위로도 builder에서 세팅이 가능하다.

 

MockMvc 내부 구조

public final class MockMvc {
    static final String MVC_RESULT_ATTRIBUTE = MockMvc.class.getName().concat(".MVC_RESULT_ATTRIBUTE");
    private final TestDispatcherServlet servlet;
    private final Filter[] filters;
    private final ServletContext servletContext;
    
    ...이하 생략
}

 

생성 테스트

@DisplayName("생성 테스트")
@Test
public void testPost() throws Exception {
    //given
    String url = "/api/article";

    ArticleRequest req = new ArticleRequest();
    req.setTitle("testTitle");
    req.setContent("testContent");

    // RequestDto를 Json 타입으로 변환
    String requestBody = mapper.writeValueAsString(req);
    
    //when
    
    //MockMvc 요청
    ResultActions resultActions = mockMvc.perform(
            post(url)
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(requestBody)
    );
    
    //Service 로직
	List<ArticleResponse> all = service.findAll();
    
    //then
    
    //Mock 검증 (Json 타입으로 반환되는 응답을 검증할 수도 있음)
    resultActions.andExpect(status().isCreated());

    //Junit 검증
    assertThat(all.get(0).getTitle()).isEqualTo("testTitle");
    assertThat(all.get(0).getContent()).isEqualTo("testContent");
}

 

mockMvc.perform() 메서드에 Request 객체를 build 하여 테스트 요청을 넣으면

검증이 가능한 ResultActions 객체를 반환한다.

 

Request는 Http메서드, 컨텐츠 타입, 바디값,  쿠키, 해더 등등 Http 요청에 포함되는 값들을 세팅할 수 있다.

 

기타 테스트 코드

@DisplayName("글 수정")
    @Test
    public void update() throws Exception {
        //given
        String url = "/api/article/{articleId}";

        Article save = repository.save(
                Article.builder()
                        .title("test1")
                        .content("test1")
                        .build());
        UpdateArticleRequest updateArticleRequest = new UpdateArticleRequest();
        updateArticleRequest.setTitle("newTest");
        updateArticleRequest.setContent("newContent");
        //when
        ResultActions resultActions = mockMvc.perform(
                put(url,save.getId())
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(mapper.writeValueAsString(updateArticleRequest))
        );

        //then
        resultActions
                .andExpect(status().isOk());

        Article article = repository.findById(save.getId()).orElseThrow();
        assertThat(article.getId()).isEqualTo(save.getId());
    }
    @DisplayName("글 삭제")
    @Test
    public void deleteArticle() throws Exception {
        //given
        String url = "/api/article/{articleId}";

        Article save = repository.save(
                Article.builder()
                        .title("test1")
                        .content("test1")
                        .build());
        //when

        ResultActions resultActions = mockMvc.perform(delete(url, save.getId()));

        resultActions.andExpect(status().isNoContent());
        List<Article> articles = repository.findAll();
        
        //then
        assertThat(articles).isEmpty();
    }
    @DisplayName("글 조회")
    @Test
    public void getAll() throws Exception {
        //given
        String url = "/api/article";

        repository.save(
                Article.builder()
                        .title("test1")
                        .content("test1")
                        .build());

        //when
        ResultActions resultActions = mockMvc.perform(
                get(url)
                        .contentType(MediaType.APPLICATION_JSON)
        );

        //then
        resultActions
                .andExpect(status().isOk())
                .andExpect(jsonPath("$[0].title").value("test1"))
                .andExpect(jsonPath("$[0].content").value("test1"));
    }

 

 

'JUnit, TDD , 클린코드 연습' 카테고리의 다른 글

프로젝트 테스트 코드 작성  (0) 2024.04.27
문자열 계산기  (0) 2023.02.09