Spring Boot Controller test (with JUnit5)

최민길(Gale)·2023년 1월 10일
4

Spring Boot 적용기

목록 보기
7/46

안녕하세요 오늘은 Spring Boot에서 Controller를 생성해보고 이를 테스트해보는 방법에 대해서 포스팅하려고 합니다.


출처 : https://junit.org/junit5/docs/current/user-guide/

우선 저는 어노테이션으로 간단하게 제공하여 편하게 테스트할 수 있는 Java 전용 단위 테스트 도구인 JUnit을 사용했습니다. JUnit의 경우 JUnit4와 JUnit5가 있는데, 두 버전의 차이는 내부 엔진이 다르며 JUnit4의 경우 단일 모듈로 구성된 것에 비해 JUnit5는 3가지 모듈, JUnit Platform + JUnit Jupiter + JUnit Vintage으로 구성됩니다. JUnit Platform은 JVM의 테스팅 프레임워크를 시작하기 위한 기반 역할과 테스트 프레임워크를 개발하기 위한 API가 존재합니다. JUnit Jupiter는 테스트를 실행하기 위한 테스트 엔진을 제공하며, JUnit Vintage는 이전 버전의 테스트 엔진을 제공합니다. 저는 최신 버전의 강력함과 이전 번과의 호환이 가능한 JUnit5를 이용하여 테스트를 진행하였습니다.

package com.example.test;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello(){
        return "hello";
    }
}

우선 간단하게 hello 문자열을 출력하는 Controller를 만들어보겠습니다. @RestController 어노테이션으로 리턴값을 바로 HttpResponse로 전달하고 @GetMapping 어노테이션을 통해 URI 주소를 입력받았습니다.


다음은 이어서 Test 클래스를 만들어 컨트롤러가 정상적으로 동작하는지 단위 테스트를 수행했습니다. 테스트 클래스를 만드는 방법은 위의 이미지처럼 테스트 클래스를 만들고자 하는 클래스에 들어가 클래스 이름을 우클릭하여 생성 -> 테스트를 눌러 테스트 클래스를 만드실 수 있습니다.

package com.example.test;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;

// MockMvcRequestBuilders의 정적 메소드를 이용하여 RequestBuilder 객체를 만들어 perform에 인자로서 대입
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@ExtendWith(SpringExtension.class)
// Extension 사용을 위한 어노테이션 (ex BeforeAllCallback 등 Lifecycle callbacks 호출 시)
// JUnit4에서는 RunWith, JUnit5에서는 ExtendWith
// SpringExtension.class & MockitoExtension.class 두 종류가 있음
// SpringBootTest 없이 가볍게 테스트하고 싶을 때는 MockitoExtension, 일반적인 경우는 SpringExtension (좀 더 공부 필요)
// 참고 링크 : https://stackoverflow.com/questions/60308578/what-is-the-difference-between-extendwithspringextension-class-and-extendwit

@AutoConfigureMockMvc
// MockMvc 제어하는 어노테이션
// Mock : 테스트를 위해 실제 객체와 비슷한 객체를 만드는 것
// 같은 기능을 수행하는 어노테이션으로 @WebMvcTest 존재
// @WebMvcTest는 가볍게 테스트할 때 사용, @Controller 어노테이션만 테스트 가능
// @AutoConfigureMockMvc는 @Controller 뿐만 아니라 @Service, @Repository 모두 테스트 가능
// 참고 링크 : https://we1cometomeanings.tistory.com/65

@SpringBootTest
// 테스트에 필요한 거의 모든 의존성 제공
// 사용 시 @ExtendWith(SpringExtension.class) 이미 포함하고 있기 때문에 @ExtensionWith을 사용하지 않아도 됨
// Autowired 허용하여 객체 의존성 주입
// 참고 링크 : https://www.inflearn.com/questions/211302/springboottest%EC%97%90%EC%84%9C-%EC%96%B4%EB%96%BB%EA%B2%8C-autowired%EA%B0%80-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94%EC%A7%80-%EA%B6%81%EA%B8%88%ED%95%A9%EB%8B%88%EB%8B%A4

class HelloControllerTest {

   @Autowired
   // MockMvc 객체 의존성 주입
   // SpringBootTest 어노테이션이 없다면 의존성 주입이 되지 않아 값이 null로 처리됨
   // 코드 입력 시 오류난 것 처럼 빨간 밑줄이 생기면서 " 'MockMvc' 타입의 bean을 찾을 수 없습니다. " 문구가 나오지만 정상 실행됨
   // 왜 실행되는지에 대해선 좀 더 공부 필요
   private MockMvc mvc;

   @Test
   // JUnit5의 테스트 수행
   // 여러 테스트 케이스 만들어서 값 안에 추가해서 테스트 가능
   public void helloControllerTest() throws Exception{
       mvc.perform(get("/hello")) // 만들어놓은 HelloController에 GET, POST 등의 메소드와 함께 Mock 이용하여 가상으로 접속
               .andExpect(status().isOk());   // 실행 결과 상태값 출력
       // 다른 여러 옵션 존재, 원하는 옵션을 추가해서 사용하면 됨
       // 참고 링크 : https://scshim.tistory.com/321
   }
}

위의 코드는 테스트 클래스에 기입한 코드입니다. Controller를 테스트하기 위해서는 Mock이라는 가상의 객체를 만들어 접속을 테스트하는 방식으로 진행됩니다. Mock을 제어하기 위한 @AutoConfigureMockMvc 어노테이션을 설정하고 테스트를 위해 @SpringBootTest 어노테이션도 추가했습니다. 코드 내부에서는 MockMvc 객체를 @Autowired하여 의존성 주입 후 @Test 어노테이션을 통해 테스트를 수행합니다. 이 때 perform() 메소드를 통해 입력받을 URI를 설정하고, 실행 결과에 대해서도 확인할 수 있도록 옵션을 추가합니다. 각 코드 별로 작동하는 역할을 기입했으니 세부적인 내용은 코드를 살펴보시면 좋을 것 같습니다.

코드 실행 결과 테스트가 정상적으로 통과되었습니다.


만약 URI 값을 존재하지 않는 "/hello1"로 변경한다면 다음과 같이 테스트 실패가 나타나게 되면서 각 파라미터 별 상태값과 리턴 코드에 대해서 확인할 수 있습니다. 이를 통해 오류 또는 예외 처리에 대해서 더 편하고 확실하게 진행할 수 있습니다.

코드 실행 결과 정상적으로 실행됨을 확인할 수 있습니다. 이상으로 오늘의 포스팅 마치도록 하겠습니다.

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

2개의 댓글

comment-user-thumbnail
2023년 2월 22일

안녕하세요. 포스팅 잘 봤습니다. 혹시, 테스팅을 적용해나가시면서 업데이트 되는 부분이 있었을까요?
MockMvc에 @Autowired 걸어 두신 내용에 관해 궁금해져서요.
" // 왜 실행되는지에 대해선 좀 더 공부 필요
private MockMvc mvc; "
답변 남겨주시면 정말 감사드리겠습니다.

1개의 답글