본문 바로가기

Backend/Spring

Spring Boot JUnit 5 MockMvc Test

스프링 부트에서 테스트 코드를 작성해볼거에요.

굉장히 많은 방법들이 있어요.

그 중에 가장 기본적인 방법으로 알려져있는 JUnit Framework를 사용해보겠습니다.

아마 대부분 스프링 부트로 개발을 하고 있다면 개발한 Controller를 테스트하고 싶을거에요.

Controller를 테스트하는 방법 역시 여러가지가 있지만 그 중에 기본으로 알려진 MockMvc를 사용하겠습니다.

AbstractControllerTest

src/test/java 소스 폴더 밑에 패키지를 만들어서 넣어주면 됩니다.

테스트할 때 필요한 공통 설정 파일이구요.

설정하는 방법은 대표적으로 두 가지에요.

  • AutoConfiguration
  • Customizing

AutoConfiguration

아주 간단하게 테스트할 때는 아래와 같이 설정하면 바로 mockMvc 객체를 사용할 수 있어요.

 

@SpringBootTest
@AutoConfigureMockMvc
public abstract class AbstractControllerTest {
    
	@Autowired
	protected MockMvc mockMvc;

}

 

Customizing

위의 오토컨피그로 설정을 하면 MockMvc를 커스텀하기가 어려워요.

그래서 MockMvcBuilders를 활용해서 직접 MockMvc 인스턴스를 생성하겠습니다.

가장 기본이 되는 설정만 추가하였구요.

addFilter(...) UTF-8 인코딩을 해주지 않으면 테스트 수행 시에 body의 한글이 깨집니다.

alwaysDo(print()) 는 항상 콘솔에 테스트 결과를 찍어주라는 의미이구요.

 

@SpringBootTest
public abstract class AbstractControllerTest {

	protected MockMvc mockMvc;
	
	abstract protected Object controller();

	@BeforeEach
	private void setup() {
		mockMvc = MockMvcBuilders.standaloneSetup(controller())
			.addFilter(new CharacterEncodingFilter(StandardCharsets.UTF_8.name(), true))
			.alwaysDo(print())
			.build();
	}
    
}

BoardControllerTest

내가 테스트하고 싶은 컨트롤러 + Test 라는 이름의 클래스를 생성해주세요. (다른 이름도 상관없습니다.)

위에서 만들어두었던 AbstractControllerTest를 상속받습니다.

추상 메서드 구현 부분에 테스트할 컨트롤러 인스턴스를 리턴해주면 끝입니다.

이제 @Test 어노테이션을 붙여서 테스트하고 싶은 API의 메서드를 생성하면 됩니다.

 

public class BoardControllerTest extends AbstractControllerTest {

	@Autowired
	private BoardController boardController;

	@Override
	protected Object controller() {
		return boardController;
	}
    
	@Test
	public void getBoard() throws Exception {
		// TODO
	}

	@Test
	public void getBoards() throws Exception {
		// TODO
	}

	@Test
	public void postBoard() throws Exception {
		// TODO
	}

	@Test
	public void updateBoard() throws Exception {
		// TODO
	}

	@Test
	public void deleteBoard() throws Exception {
		// TODO
	}

}

 

BoardControllerTest 에서 이제 원하는 API 의 테스트 소스를 만들어내면 되요.

간단하게 위의 메서드를 구현했습니다.

 

@Test
public void getBoard() throws Exception {
	mockMvc.perform(get("/board/{boardId}", 1L));
}

@Test
public void getBoards() throws Exception {
	MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
	params.add("keyword", "제목");
	params.add("offset", "1");
	params.add("limit", "5");

	mockMvc.perform(
		get("/board")
		.params(params)
		);
}

@Test
public void postBoard() throws Exception {
	ObjectNode content = mapper.createObjectNode();
	content.put("title", "제목신규");
	content.put("content", "내용신규");
		
	mockMvc.perform(
		post("/board")
		.content(mapper.writeValueAsString(content))
		.contentType(MediaType.APPLICATION_JSON)
		);
}

@Test
public void updateBoard() throws Exception {
	ObjectNode content = mapper.createObjectNode();
	content.put("title", "제목수정");
	content.put("content", "내용수정");

	mockMvc.perform(
		patch("/board/{boardId}", 1L)
		.content(mapper.writeValueAsString(content))
		.contentType(MediaType.APPLICATION_JSON)
        );
}

@Test
public void deleteBoard() throws Exception {
	mockMvc.perform(
		delete("/board/{boardId}", 100L)
		);
}