SpringBoot 컨트롤러(Controller) 테스트 코드

KDG: First things first!·2024년 9월 12일
0

테스트 코드

목록 보기
2/2

[WebMVC 구조]

이번 시간에는 WebMVC 구조의 하나인 Controller 부분에 대한 테스트 코드를 작성하는 방법에 대해 알아보자.




Controller Test


컨트롤러는 사용자 입력을 받아 비즈니스 로직을 호출하고, 그 결과를 사용자에게 반환하는 역할을 한다.

컨트롤러 테스트는 웹 애플리케이션에서 사용자가 요청을 보낼 때 이를 처리하는 컨트롤러 레이어가 올바르게 작동하는지 검증하는 테스트이다.

(컨트롤러가 예상대로 작동하는지, 웹 요청과 응답이 제대로 이루어지는지를 검증한다.)



package org.example.expert.domain.comment.service.controller;

import org.example.expert.domain.comment.controller.CommentController;
import org.example.expert.domain.comment.service.CommentService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;

import java.util.List;

import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(CommentController.class) // 컨트롤러 테스트 환경 지정
public class CommentControllerTest {

    @Autowired
    private MockMvc mockMvc; // MockMvc를 사용하여 HTTP 요청을 흉내

    @MockBean // 외부 의존성에 영향을 받지 않도록 기존 스프링 컨텍스트의 Bean을 Mock 객체로 교체
    private CommentService commentService;

    @Test
    public void 댓글_조회() throws Exception {
        // given
        long todoId = 1L;

        given(commentService.getComments(anyLong())).willReturn(List.of());

        // when
        ResultActions resultActions = mockMvc.perform(get("/todos/{todoId}/comments", todoId));

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

WebMvcTest

@WebMvcTest(테스트할 컨트롤러.class) : 해당 컨트롤러만 테스트할 환경으로 설정한다.


@ExtendWith(MockitoExtension.class) vs @WebMvcTest

@ExtendWith(MockitoExtension.class) : 의존성 주입을 위해 객체를 직접 가짜인 Mock 객체로 초기화하고 특정 객체 테스트를 진행한다.

@WebMvcTest : 스프링 MVC를 위한 테스트로 컨트롤러와 관련된 애들만 빈으로 등록하고, Service, Repository와 같은 레이어는 빈으로 등록하지 않아 의존성을 제거한다.

즉, 스프링 컨텍스트에서 컨트롤러와 관련된 애들만 빈으로 등록하고 테스트한다.
(@WebMvcTest는 빈으로 등록해서 사용하는 통합 테스트의 일종이다.)



MockBean

@MockBean: 외부 의존성에 영향을 받지 않도록 Spring 컨텍스트에서 관리되는 Bean을 mock 객체로 교체한다.


@Mock vs @MockBean

@Mock : 단위 테스트에서 사용되며 Mock 객체를 직접 생성하여 사용하기 때문에 스프링 컨텍스트(컨테이너)와 관련이 없다.

@MockBean : 통합 테스트에서 사용되고 Mock 객체를 생성하고, 스프링 컨텍스트에 등록하여
관련된 객체와 연결하여 통합 테스트를 수행할 수 있다.

➜ 통합 테스트에서 컨테이너가 필요하기 때문에 @MockBean을 통해 빈을 등록하고, 단위 테스트는 컨테이너가 필요없기 때문에 @Mock을 통해 각 객체를 생성하면 된다.



MockMvc

MockMvc : HTTP 요청을 모의(Mock)하여 실제 서블릿 컨테이너를 사용하지 않고도 웹 애플리케이션의 컨트롤러를 테스트할 수 있게 해준다.

MockMvc를 사용하여 다양한 HTTP 요청을 시뮬레이션하고 응답을 검증할 수 있다.


(MockMvc를 이용한 Get 요청 예시)


 // when & then
        mockMvc.perform(get("/movies/{id}", movieId))  // GET 요청 시뮬레이션
            .andExpect(status().isOk())  // 응답 상태 코드가 200인지 확인
            .andExpect(jsonPath("$.title").value("Inception"))  // 반환된 JSON의 title 값 검증
            .andExpect(jsonPath("$.genre").value("Sci-Fi"))  // 반환된 JSON의 genre 값 검증
            .andDo(print()); // 콘솔 창 출력

(MockMvc를 이용한 Post 요청 예시)


 // when & then
        mockMvc.perform(post("/movies")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(movie)))  // JSON 변환 후 요청 본문에 포함
            .andExpect(status().isCreated())  // 응답 상태 코드가 201인지 확인
            .andExpect(jsonPath("$.id").value(1))  // 반환된 JSON의 id 값 검증
            .andExpect(jsonPath("$.title").value("Inception"))  // 반환된 JSON의 title 값 검증
            .andExpect(jsonPath("$.genre").value("Sci-Fi"))  // 반환된 JSON의 genre 값 검증
            .andDo(print()); // 콘솔 창 출력 

※ mockMvc.의 결과값은 ResultActions이다.

profile
알고리즘, 자료구조 블로그: https://gyun97.github.io/

0개의 댓글