본문 바로가기
dev/spring

RestTestClient를 사용하여 Spring Rest API 테스트 작성하기

by igooo 2026. 1. 5.
728x90

개요

RestTestClient는 Spring Framework 7에서 새롭게 도입된 통합 테스트 도구로, Spring REST API를 손쉽게 테스트할 수 있게 해 준다. 기존에 MockMvc와 WebTestClient의 장점을 하나로 합쳐 단순하고 직관적인 API를 제공하여 쉽게 테스트를 작성할 수 있게 해 준다.

이번 게시글에서는 RestTestClient의 각 상황에 맞는 사용법과 왜 사용해야 하는지에 대하여 알아보자. 자세한 사항은 아래 문서를 참고한다.

공식 문서 : https://docs.spring.io/spring-framework/reference/testing/resttestclient.html

 

RestTestClient를 사용해야 하는 이유는 무엇일까?

  • 모든 유형의 테스트를 위한 일관된 API를 제공한다.
  • 유창하고 읽기 쉬운 구문을 제공한다.
  • 단위 테스트, 통합 테스트 및 end-to-end 테스트 모두 작성이 가능하다.
  • 배우고 사용하기 쉽다. 

아래 각 상황에 맞는 예제에 대하여 하나씩 알아보도록 하자.

 

Gettng Started

사전 준비 

Spring Boot 4.1로 프로젝트를 생성하고 Web관련 Starter를 추가한다.

plugins {
	id 'java'
	id 'org.springframework.boot' version '4.0.1'
	id 'io.spring.dependency-management' version '1.1.7'
}

{
	implementation 'org.springframework.boot:spring-boot-starter-webmvc'

	testImplementation 'org.springframework.boot:spring-boot-starter-webmvc'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

 

테스트로 사용할 API Controller를 작성한다.

@RestController
@RequestMapping("/users")
class UserController {
	private final UserService userService;

	UserController(UserService userService) {
		this.userService = userService;
	}

	@GetMapping
	List<User> findAll() {
		return this.userService.findAll();
	}

	@GetMapping("/{id}")
	User findById(@PathVariable("id") int id) {
		return this.userService.findBydId(id);
	}
}

 

 

테스트 작성

Bind To Controller

Controller의 로직만 빠르게 테스트할 때 사용한다. (기존 Mockito를 사용한 테스트와 비슷하다.)

class SimpleControllerTests {
	private RestTestClient client;
	
	private UserService userService;
	
	@BeforeEach
	void setup() {
		this.userService = mock(UserService.class);
		
		this.client = RestTestClient.bindToController(new UserController(this.userService)).build();
	}
	
	@Test
	void findById() {
		var id = 1;
		
		// Given
		given(this.userService.findBydId(id)).willReturn(new User(id));
		
		// When & Then
		this.client.get()
			.uri("/users/1")
			.exchange()
			.expectStatus()
			.isOk()
			.expectHeader()
			.contentType(MediaType.APPLICATION_JSON)
			.expectBody()
			.json("{\"id\":1}")
			.returnResult();
	}
		
}

 

Bind to MockMvc

Spring MVC 기능(유효성 검사, 보안, 예외 처리 등)을 사용하여 테스트를 작성한다.

@WebMvcTests(UserController.class)
class MockMvcControllerTests {
	@Autowired
	private MockMvc mockMvc;
	
	@MockitoBean
	private UserService userService;
	
	private RestTestClient client;
	
	@BeforeEach
	void setup() {
		this.client = RestTestClient.bindTo(this.mockMvc).build();
	}
	
	@Test
	void findAll() {
		// Given
		given(this.userService.findAll()).willReturn(List.of(new User(0), new User(1)));
		
		// When
		var users = this.client.get()
				.uri("/users")
				.exchange()
				.expectStatus()
				.isOk()
				.expectBody(new ParameterizedTypeReference<List<User>>() {})
				.returnResult()
				.getResponseBody();
		
		// Then
		assertThat(users).hasSize(2);
		assertThat(users.getFirst().id()).isEqualTo(2);
	}
	
	@Test
	void invalideInput() {
		var users = this.client.get()
				.uri("/users")
				.exchange()
				.expectStatus()
				.isBadRequest();
	}
}

 

Bind To ApplicationContext

실제 서비스와 데이터베이스를 사용하여 애플리케이션 전체를 테스트한다.

HTTP 연결을 사용하지 않는다.
@SpringBootTest
class ApplicationContextControllerTests {
	@Autowired
	private WebApplicationContext context;
	
	private RestTestClient client;
	
	@BeforeEach
	void setup() {
		this.client = RestTestClient.bindToApplicationContext(this.context).build();
	}
	
	@Test
	void findAll() {
		var users = this.client.get()
				.uri("/users")
				.exchange()
				.expectStatus()
				.isOk()
				.expectBody(new ParameterizedTypeReference<List<User>>() {})
				.returnResult()
				.getResponseBody();
		
		assertThat(users).hasSize(2);
		assertThat(users.getFirst().id()).isEqualTo(2);
	}
}

 

Bind To Server

실제 HTTP 요청을 포함한 모든 기능을 테스트한다.

CORS, 헤더 또는 압축과 같은 HTTP 관련 기능을 포함하여 테스트를 작성할 수 있다.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ServerControllerTests {
	@LocalServerPort
	private int serverPort;
	
	private RestTestClient client;
	
	@BeforeEach
	void setup() {
		this.client = RestTestClient.bindToServer().baseUrl("http://localhost:" + this.serverPort).build();
	}
	
	@Test
	void findAll() {
		var users = this.client.get()
				.uri("/users")
				.exchange()
				.expectStatus()
				.isOk()
				.expectBody(new ParameterizedTypeReference<List<User>>() {})
				.returnResult()
				.getResponseBody();
		
		assertThat(users).hasSize(2);
		assertThat(users.getFirst().id()).isEqualTo(0);
	}

}

 

 

마무리

각 테스트 방법은 각각의 장단점이 존재한다. 그리고 진행하는 프로젝트와 CI/CD 구성에 따라 상황에 맞는 테스트 코드를 작성할 필요가 있을 것이다. 비즈니스 로직이 들어가는 코드에는 대부분 테스트를 작성하지만 Controller는 로직이 많이 넣지 않기 때문에 테스트를 많이 작성하지는 않았을 수 있다. RestTestClient를 사용하여 Controller에도 상황에 맞는 테스트 코드를 작성해 보자.

728x90

'dev > spring' 카테고리의 다른 글

Spring Boot 4 모듈화  (0) 2025.12.11
Spring - Path Prefix  (0) 2025.08.18
Spring Framework 7.0.0 API Versioning  (0) 2025.07.31
Spring Framework 7.0 - Resilience Features (회복력 기능)  (2) 2025.07.27
Jackson 3.0.0 알아보기  (0) 2025.07.15