본문 바로가기

Framework/Spring

[Spring] 컨트롤러 단위 테스트: @WebMvcTest와 @SpringBootTest의 선택과 활용 -컴도리돌이

728x90
728x90
 

작심삼주 오블완 챌린지

오늘 블로그 완료! 21일 동안 매일 블로그에 글 쓰고 글력을 키워보세요.

www.tistory.com


작업한 로직을 테스트하기 위해 컨트롤러에 단위 테스트 클래스를 작성하고, @WebMvcTest로 URL에 요청 테스트를 시도해 봤습니다. 하지만 예상보다 많은 난관이 있어 처음에는 쉽게 진행되지 않았습니다. 특히 여러 서비스와 유틸리티 클래스들을 어떻게 처리할지에 대해 고민이 많았네요. 🥲

No qualifying bean of type available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

 

위와 같은 에러가 발생하면서 테스트가 중단되었고, 이에 대한 해결책을 찾아야 했습니다. 😂 이 에러는 기본적으로 Spring이 주입할 수 있는 빈을 찾지 못했다는 의미입니다. @WebMvcTest는 기본적으로 컨트롤러만 로드하고, 다른 서비스나 유틸리티 클래스 같은 빈들은 로드하지 않기 때문에 발생합니다. 예를 들어, 컨트롤러 내에서 사용하는 서비스가 @Autowired로 주입되어 있을 경우, 해당 서비스가 모킹 되지 않으면 이와 같은 에러가 발생할 수 있습니다.


@WebMvcTest는 컨트롤러와 관련된 빈만 로드합니다. 즉, 서비스나 유틸리티 클래스 같은 다른 빈들은 로드되지 않기 때문에, 테스트에서 실제로 필요한 빈을 @MockBean으로 추가해야 합니다.

@WebMvcTest
public class ControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private TestService testService;

    @Test
    public void test_success() throws Exception {
        // Mocking testService response
        when(testService.getList(any(Request.class))).thenReturn(new TestResponse());

        mockMvc.perform(get("/api/v1/getList")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
                .andDo(print());
    }
}

 

위와 같이 필요한 빈만 @MockBean으로 주입하고, 나머지 빈은 실제 빈으로 테스트를 수행할 수 있습니다. 이렇게 하면 테스트 범위가 좁아지고, 관리가 용이합니다.

 

하지만, 주입해야 할 빈이 50개를 넘을 경우에는 각 빈을 하나하나 @MockBean으로 추가하는 것이 매우 비효율적이고, 테스트가 복잡해집니다. 이런 상황에서 더 나은 방법을 찾아야겠죠? 🤔

@SpringBootTest 활용하기

애플리케이션 전체를 테스트하려면, @SpringBootTest를 사용하는 방법이 있습니다. @SpringBootTest는 애플리케이션 컨텍스트 전체를 로드하며, @AutoConfigureMockMvc로 MockMvc를 자동으로 설정해 줍니다. 이 방법을 사용하면, 모든 빈이 로드되며 실제 빈들을 사용하면서 테스트를 진행할 수 있습니다.

@SpringBootTest
@AutoConfigureMockMvc
public class ControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private TestService testService;

    @Test
    public void test_success() throws Exception {
        // Mock the service response
        when(testService.getList(any(Request.class))).thenReturn(new TestResponse());

        // Perform the request and verify the response
        mockMvc.perform(get("/api/v1/getList")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
                .andDo(print());
    }
}

 

@SpringBootTest는 애플리케이션 컨텍스트 전체를 로드하므로, 실제 서비스 빈을 사용하여 테스트할 수 있습니다. 이를 통해 실제 동작 환경을 구현할 수 있으며, @MockBean을 사용하지 않고 모든 빈을 테스트할 수 있습니다.

 

정리하자면, 빈이 많을 땐 @SpringBootTest와 @AutoConfigureMockMvc로 전체 애플리케이션을 로드하고, 빈이 적을 땐 @WebMvcTest와 @MockBean으로 필요한 빈만 모킹 하여 효율적인 테스트를 할 수 있습니다. 😊

728x90
728x90