| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | [[webtestclient]] | 
					
						
							|  |  |  | = WebTestClient | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | `WebTestClient` is an HTTP client designed for testing server applications. It wraps | 
					
						
							| 
									
										
										
										
											2023-04-19 23:26:17 +08:00
										 |  |  | Spring's xref:web/webflux-webclient.adoc[WebClient] and uses it to perform requests | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | but exposes a testing facade for verifying responses. `WebTestClient` can be used to | 
					
						
							|  |  |  | perform end-to-end HTTP tests. It can also be used to test Spring MVC and Spring WebFlux | 
					
						
							|  |  |  | applications without a running server via mock server request and response objects. | 
					
						
							| 
									
										
										
										
											2018-02-15 06:32:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-19 02:24:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 21:15:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | [[webtestclient-setup]] | 
					
						
							|  |  |  | == Setup | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | To set up a `WebTestClient` you need to choose a server setup to bind to. This can be one | 
					
						
							|  |  |  | of several mock server setup choices or a connection to a live server. | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-19 02:24:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | [[webtestclient-controller-config]] | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | === Bind to Controller | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | This setup allows you to test specific controller(s) via mock request and response objects, | 
					
						
							|  |  |  | without a running server. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | For WebFlux applications, use the following which loads infrastructure equivalent to the | 
					
						
							| 
									
										
										
										
											2023-04-19 23:26:17 +08:00
										 |  |  | xref:web/webflux/dispatcher-handler.adoc#webflux-framework-config[WebFlux Java config], registers the given | 
					
						
							|  |  |  | controller(s), and creates a xref:web/webflux/reactive-spring.adoc#webflux-web-handler-api[WebHandler chain] | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | to handle requests: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 	WebTestClient client = | 
					
						
							|  |  |  | 			WebTestClient.bindToController(new TestController()).build(); | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 	val client = WebTestClient.bindToController(TestController()).build() | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | For Spring MVC, use the following which delegates to the | 
					
						
							| 
									
										
										
										
											2023-11-21 22:59:24 +08:00
										 |  |  | {spring-framework-api}/test/web/servlet/setup/StandaloneMockMvcBuilder.html[StandaloneMockMvcBuilder] | 
					
						
							| 
									
										
										
										
											2023-04-19 23:26:17 +08:00
										 |  |  | to load infrastructure equivalent to the xref:web/webmvc/mvc-config.adoc[WebMvc Java config], | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | registers the given controller(s), and creates an instance of | 
					
						
							| 
									
										
										
										
											2024-06-21 18:50:36 +08:00
										 |  |  | xref:testing/mockmvc.adoc[MockMvc] to handle requests: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 	WebTestClient client = | 
					
						
							|  |  |  | 			MockMvcWebTestClient.bindToController(new TestController()).build(); | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 	val client = MockMvcWebTestClient.bindToController(TestController()).build() | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-19 02:24:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | [[webtestclient-context-config]] | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | === Bind to `ApplicationContext` | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | This setup allows you to load Spring configuration with Spring MVC or Spring WebFlux | 
					
						
							|  |  |  | infrastructure and controller declarations and use it to handle requests via mock request | 
					
						
							|  |  |  | and response objects, without a running server. | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | For WebFlux, use the following where the Spring `ApplicationContext` is passed to | 
					
						
							| 
									
										
										
										
											2023-11-21 22:59:24 +08:00
										 |  |  | {spring-framework-api}/web/server/adapter/WebHttpHandlerBuilder.html#applicationContext-org.springframework.context.ApplicationContext-[WebHttpHandlerBuilder] | 
					
						
							| 
									
										
										
										
											2023-04-19 23:26:17 +08:00
										 |  |  | to create the xref:web/webflux/reactive-spring.adoc#webflux-web-handler-api[WebHandler chain] to handle | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | requests: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | 	@SpringJUnitConfig(WebConfig.class) // <1> | 
					
						
							| 
									
										
										
										
											2019-08-31 20:47:49 +08:00
										 |  |  | 	class MyTests { | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-31 20:47:49 +08:00
										 |  |  | 		WebTestClient client; | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | 		@BeforeEach | 
					
						
							| 
									
										
										
										
											2019-08-31 20:47:49 +08:00
										 |  |  | 		void setUp(ApplicationContext context) {  // <2> | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 			client = WebTestClient.bindToApplicationContext(context).build(); // <3> | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | <1> Specify the configuration to load | 
					
						
							|  |  |  | <2> Inject the configuration | 
					
						
							|  |  |  | <3> Create the `WebTestClient` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-06 09:19:47 +08:00
										 |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	@SpringJUnitConfig(WebConfig::class) // <1> | 
					
						
							|  |  |  | 	class MyTests { | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | 		lateinit var client: WebTestClient | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		@BeforeEach | 
					
						
							| 
									
										
										
										
											2019-08-31 20:47:49 +08:00
										 |  |  | 		fun setUp(context: ApplicationContext) { // <2> | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | 			client = WebTestClient.bindToApplicationContext(context).build() // <3> | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | <1> Specify the configuration to load | 
					
						
							|  |  |  | <2> Inject the configuration | 
					
						
							|  |  |  | <3> Create the `WebTestClient` | 
					
						
							| 
									
										
										
										
											2023-05-06 09:19:47 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | For Spring MVC, use the following where the Spring `ApplicationContext` is passed to | 
					
						
							| 
									
										
										
										
											2023-11-21 22:59:24 +08:00
										 |  |  | {spring-framework-api}/test/web/servlet/setup/MockMvcBuilders.html#webAppContextSetup-org.springframework.web.context.WebApplicationContext-[MockMvcBuilders.webAppContextSetup] | 
					
						
							| 
									
										
										
										
											2024-06-21 18:50:36 +08:00
										 |  |  | to create a xref:testing/mockmvc.adoc[MockMvc] instance to handle | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | requests: | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	@ExtendWith(SpringExtension.class) | 
					
						
							|  |  |  | 	@WebAppConfiguration("classpath:META-INF/web-resources") // <1> | 
					
						
							|  |  |  | 	@ContextHierarchy({ | 
					
						
							|  |  |  | 		@ContextConfiguration(classes = RootConfig.class), | 
					
						
							|  |  |  | 		@ContextConfiguration(classes = WebConfig.class) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	class MyTests { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		@Autowired | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | 		WebApplicationContext wac; // <2> | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		WebTestClient client; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		@BeforeEach | 
					
						
							|  |  |  | 		void setUp() { | 
					
						
							|  |  |  | 			client = MockMvcWebTestClient.bindToApplicationContext(this.wac).build(); // <3> | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | <1> Specify the configuration to load | 
					
						
							|  |  |  | <2> Inject the configuration | 
					
						
							|  |  |  | <3> Create the `WebTestClient` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-06 09:19:47 +08:00
										 |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	@ExtendWith(SpringExtension.class) | 
					
						
							|  |  |  | 	@WebAppConfiguration("classpath:META-INF/web-resources") // <1> | 
					
						
							|  |  |  | 	@ContextHierarchy({ | 
					
						
							|  |  |  | 		@ContextConfiguration(classes = RootConfig.class), | 
					
						
							|  |  |  | 		@ContextConfiguration(classes = WebConfig.class) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	class MyTests { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		@Autowired | 
					
						
							|  |  |  | 		lateinit var wac: WebApplicationContext; // <2> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		lateinit var client: WebTestClient | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		@BeforeEach | 
					
						
							|  |  |  | 		fun setUp() { // <2> | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | 			client = MockMvcWebTestClient.bindToApplicationContext(wac).build() // <3> | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | <1> Specify the configuration to load | 
					
						
							|  |  |  | <2> Inject the configuration | 
					
						
							|  |  |  | <3> Create the `WebTestClient` | 
					
						
							| 
									
										
										
										
											2023-05-06 09:19:47 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [[webtestclient-fn-config]] | 
					
						
							|  |  |  | === Bind to Router Function | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | This setup allows you to test <<web-reactive.adoc#webflux-fn, functional endpoints>> via | 
					
						
							|  |  |  | mock request and response objects, without a running server. | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | For WebFlux, use the following which delegates to `RouterFunctions.toWebHandler` to | 
					
						
							|  |  |  | create a server setup to handle requests: | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	RouterFunction<?> route = ... | 
					
						
							|  |  |  | 	client = WebTestClient.bindToRouterFunction(route).build(); | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	val route: RouterFunction<*> = ... | 
					
						
							|  |  |  | 	val client = WebTestClient.bindToRouterFunction(route).build() | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | For Spring MVC there are currently no options to test | 
					
						
							| 
									
										
										
										
											2023-04-19 23:26:17 +08:00
										 |  |  | xref:web/webmvc-functional.adoc[WebMvc functional endpoints]. | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-19 02:24:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | [[webtestclient-server-config]] | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | === Bind to Server | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | This setup connects to a running server to perform full, end-to-end HTTP tests: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 	client = WebTestClient.bindToServer().baseUrl("http://localhost:8080").build(); | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	client = WebTestClient.bindToServer().baseUrl("http://localhost:8080").build() | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [[webtestclient-client-config]] | 
					
						
							| 
									
										
										
										
											2020-09-01 04:14:45 +08:00
										 |  |  | === Client Config | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | In addition to the server setup options described earlier, you can also configure client | 
					
						
							|  |  |  | options, including base URL, default headers, client filters, and others. These options | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | are readily available following `bindToServer()`. For all other configuration options, | 
					
						
							|  |  |  | you need to use `configureClient()` to transition from server to client configuration, as | 
					
						
							|  |  |  | follows: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 	client = WebTestClient.bindToController(new TestController()) | 
					
						
							|  |  |  | 			.configureClient() | 
					
						
							|  |  |  | 			.baseUrl("/test") | 
					
						
							|  |  |  | 			.build(); | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	client = WebTestClient.bindToController(TestController()) | 
					
						
							|  |  |  | 			.configureClient() | 
					
						
							|  |  |  | 			.baseUrl("/test") | 
					
						
							|  |  |  | 			.build() | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 21:15:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | [[webtestclient-tests]] | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | == Writing Tests | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-19 23:26:17 +08:00
										 |  |  | `WebTestClient` provides an API identical to xref:web/webflux-webclient.adoc[WebClient] | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | up to the point of performing a request by using `exchange()`. See the | 
					
						
							| 
									
										
										
										
											2023-04-19 23:26:17 +08:00
										 |  |  | xref:web/webflux-webclient/client-body.adoc[WebClient] documentation for examples on how to | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | prepare a request with any content including form data, multipart data, and more. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | After the call to `exchange()`, `WebTestClient` diverges from the `WebClient` and | 
					
						
							|  |  |  | instead continues with a workflow to verify responses. | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-18 21:33:54 +08:00
										 |  |  | To assert the response status and headers, use the following: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	client.get().uri("/persons/1") | 
					
						
							| 
									
										
										
										
											2021-08-24 00:59:41 +08:00
										 |  |  | 		.accept(MediaType.APPLICATION_JSON) | 
					
						
							|  |  |  | 		.exchange() | 
					
						
							|  |  |  | 		.expectStatus().isOk() | 
					
						
							|  |  |  | 		.expectHeader().contentType(MediaType.APPLICATION_JSON); | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 	client.get().uri("/persons/1") | 
					
						
							| 
									
										
										
										
											2021-08-24 00:59:41 +08:00
										 |  |  | 		.accept(MediaType.APPLICATION_JSON) | 
					
						
							|  |  |  | 		.exchange() | 
					
						
							|  |  |  | 		.expectStatus().isOk() | 
					
						
							|  |  |  | 		.expectHeader().contentType(MediaType.APPLICATION_JSON) | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2021-08-24 00:59:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | If you would like for all expectations to be asserted even if one of them fails, you can | 
					
						
							|  |  |  | use `expectAll(..)` instead of multiple chained `expect*(..)` calls. This feature is | 
					
						
							|  |  |  | similar to the _soft assertions_ support in AssertJ and the `assertAll()` support in | 
					
						
							|  |  |  | JUnit Jupiter. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2021-08-24 00:59:41 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	client.get().uri("/persons/1") | 
					
						
							|  |  |  | 		.accept(MediaType.APPLICATION_JSON) | 
					
						
							|  |  |  | 		.exchange() | 
					
						
							|  |  |  | 		.expectAll( | 
					
						
							|  |  |  | 			spec -> spec.expectStatus().isOk(), | 
					
						
							|  |  |  | 			spec -> spec.expectHeader().contentType(MediaType.APPLICATION_JSON) | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2024-08-08 06:37:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							|  |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	client.get().uri("/persons/1") | 
					
						
							|  |  |  | 		.accept(MediaType.APPLICATION_JSON) | 
					
						
							|  |  |  | 		.exchange() | 
					
						
							|  |  |  | 		.expectAll( | 
					
						
							|  |  |  | 			{ spec -> spec.expectStatus().isOk() }, | 
					
						
							|  |  |  | 			{ spec -> spec.expectHeader().contentType(MediaType.APPLICATION_JSON) } | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | You can then choose to decode the response body through one of the following: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | * `expectBody(Class<T>)`: Decode to single object. | 
					
						
							|  |  |  | * `expectBodyList(Class<T>)`: Decode and collect objects to `List<T>`. | 
					
						
							| 
									
										
										
										
											2023-04-19 23:26:17 +08:00
										 |  |  | * `expectBody()`: Decode to `byte[]` for xref:testing/webtestclient.adoc#webtestclient-json[JSON Content] or an empty body. | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | And perform assertions on the resulting higher level Object(s): | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 	client.get().uri("/persons") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.expectBodyList(Person.class).hasSize(3).contains(person); | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	import org.springframework.test.web.reactive.server.expectBodyList | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	client.get().uri("/persons") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.expectBodyList<Person>().hasSize(3).contains(person) | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | If the built-in assertions are insufficient, you can consume the object instead and | 
					
						
							|  |  |  | perform any other assertions: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  |     import org.springframework.test.web.reactive.server.expectBody | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 	client.get().uri("/persons/1") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.expectBody(Person.class) | 
					
						
							|  |  |  | 			.consumeWith(result -> { | 
					
						
							|  |  |  | 				// custom assertions (e.g. AssertJ)... | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	client.get().uri("/persons/1") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.expectBody<Person>() | 
					
						
							|  |  |  | 			.consumeWith { | 
					
						
							|  |  |  | 				// custom assertions (e.g. AssertJ)... | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | Or you can exit the workflow and obtain an `EntityExchangeResult`: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 	EntityExchangeResult<Person> result = client.get().uri("/persons/1") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.expectBody(Person.class) | 
					
						
							|  |  |  | 			.returnResult(); | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	import org.springframework.test.web.reactive.server.expectBody | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val result = client.get().uri("/persons/1") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk | 
					
						
							|  |  |  | 			.expectBody<Person>() | 
					
						
							|  |  |  | 			.returnResult() | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | TIP: When you need to decode to a target type with generics, look for the overloaded methods | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | that accept | 
					
						
							| 
									
										
										
										
											2023-11-21 22:59:24 +08:00
										 |  |  | {spring-framework-api}/core/ParameterizedTypeReference.html[`ParameterizedTypeReference`] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | instead of `Class<T>`. | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-05 02:58:11 +08:00
										 |  |  | [[webtestclient-no-content]] | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | === No Content | 
					
						
							| 
									
										
										
										
											2017-10-05 02:58:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | If the response is not expected to have content, you can assert that as follows: | 
					
						
							| 
									
										
										
										
											2017-10-05 02:58:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-05 02:58:11 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | 	client.post().uri("/persons") | 
					
						
							|  |  |  | 			.body(personMono, Person.class) | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 			.exchange() | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | 			.expectStatus().isCreated() | 
					
						
							|  |  |  | 			.expectBody().isEmpty(); | 
					
						
							| 
									
										
										
										
											2017-10-05 02:58:11 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | 	client.post().uri("/persons") | 
					
						
							|  |  |  | 			.bodyValue(person) | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | 			.exchange() | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | 			.expectStatus().isCreated() | 
					
						
							|  |  |  | 			.expectBody().isEmpty() | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2017-10-05 02:58:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | If you want to ignore the response content, the following releases the content without | 
					
						
							|  |  |  | any assertions: | 
					
						
							| 
									
										
										
										
											2017-10-05 02:58:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-05 02:58:11 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | 	client.get().uri("/persons/123") | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 			.exchange() | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | 			.expectStatus().isNotFound() | 
					
						
							|  |  |  | 			.expectBody(Void.class); | 
					
						
							| 
									
										
										
										
											2017-10-05 02:58:11 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | 	client.get().uri("/persons/123") | 
					
						
							| 
									
										
										
										
											2019-08-31 20:47:49 +08:00
										 |  |  | 			.exchange() | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | 			.expectStatus().isNotFound | 
					
						
							|  |  |  | 			.expectBody<Unit>() | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2017-10-05 02:58:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | [[webtestclient-json]] | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | === JSON Content | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | You can use `expectBody()` without a target type to perform assertions on the raw | 
					
						
							|  |  |  | content rather than through higher level Object(s). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To verify the full JSON content with https://jsonassert.skyscreamer.org[JSONAssert]: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	client.get().uri("/persons/1") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.expectBody() | 
					
						
							|  |  |  | 			.json("{\"name\":\"Jane\"}") | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 	client.get().uri("/persons/1") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.expectBody() | 
					
						
							|  |  |  | 			.json("{\"name\":\"Jane\"}") | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | To verify JSON content with https://github.com/jayway/JsonPath[JSONPath]: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 	client.get().uri("/persons") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.expectBody() | 
					
						
							|  |  |  | 			.jsonPath("$[0].name").isEqualTo("Jane") | 
					
						
							|  |  |  | 			.jsonPath("$[1].name").isEqualTo("Jason"); | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	client.get().uri("/persons") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.expectBody() | 
					
						
							|  |  |  | 			.jsonPath("$[0].name").isEqualTo("Jane") | 
					
						
							|  |  |  | 			.jsonPath("$[1].name").isEqualTo("Jason") | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [[webtestclient-stream]] | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | === Streaming Responses | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | To test potentially infinite streams such as `"text/event-stream"` or | 
					
						
							|  |  |  | `"application/x-ndjson"`, start by verifying the response status and headers, and then | 
					
						
							|  |  |  | obtain a `FluxExchangeResult`: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 	FluxExchangeResult<MyEvent> result = client.get().uri("/events") | 
					
						
							|  |  |  | 			.accept(TEXT_EVENT_STREAM) | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.returnResult(MyEvent.class); | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	import org.springframework.test.web.reactive.server.returnResult | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val result = client.get().uri("/events") | 
					
						
							|  |  |  | 			.accept(TEXT_EVENT_STREAM) | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.returnResult<MyEvent>() | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | Now you're ready to consume the response stream with `StepVerifier` from `reactor-test`: | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | 	Flux<Event> eventFlux = result.getResponseBody(); | 
					
						
							| 
									
										
										
										
											2017-11-21 05:28:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	StepVerifier.create(eventFlux) | 
					
						
							|  |  |  | 			.expectNext(person) | 
					
						
							|  |  |  | 			.expectNextCount(4) | 
					
						
							|  |  |  | 			.consumeNextWith(p -> ...) | 
					
						
							|  |  |  | 			.thenCancel() | 
					
						
							|  |  |  | 			.verify(); | 
					
						
							| 
									
										
										
										
											2017-10-03 21:56:13 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2019-08-31 17:31:16 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	val eventFlux = result.getResponseBody() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	StepVerifier.create(eventFlux) | 
					
						
							|  |  |  | 			.expectNext(person) | 
					
						
							|  |  |  | 			.expectNextCount(4) | 
					
						
							|  |  |  | 			.consumeNextWith { p -> ... } | 
					
						
							|  |  |  | 			.thenCancel() | 
					
						
							|  |  |  | 			.verify() | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2018-08-30 23:29:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-07 05:28:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | [[webtestclient-mockmvc]] | 
					
						
							|  |  |  | === MockMvc Assertions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `WebTestClient` is an HTTP client and as such it can only verify what is in the client | 
					
						
							|  |  |  | response including status, headers, and body. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When testing a Spring MVC application with a MockMvc server setup, you have the extra | 
					
						
							|  |  |  | choice to perform further assertions on the server response. To do that start by | 
					
						
							|  |  |  | obtaining an `ExchangeResult` after asserting the body: | 
					
						
							| 
									
										
										
										
											2017-11-07 05:28:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	// For a response with a body | 
					
						
							|  |  |  | 	EntityExchangeResult<Person> result = client.get().uri("/persons/1") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							|  |  |  | 			.expectBody(Person.class) | 
					
						
							|  |  |  | 			.returnResult(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// For a response without a body | 
					
						
							|  |  |  | 	EntityExchangeResult<Void> result = client.get().uri("/path") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectBody().isEmpty(); | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	// For a response with a body | 
					
						
							|  |  |  | 	val result = client.get().uri("/persons/1") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							|  |  |  | 			.expectStatus().isOk() | 
					
						
							| 
									
										
										
										
											2024-05-02 17:07:36 +08:00
										 |  |  | 			.expectBody<Person>() | 
					
						
							| 
									
										
										
										
											2024-04-30 20:30:39 +08:00
										 |  |  | 			.returnResult() | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// For a response without a body | 
					
						
							|  |  |  | 	val result = client.get().uri("/path") | 
					
						
							|  |  |  | 			.exchange() | 
					
						
							| 
									
										
										
										
											2024-04-30 20:30:39 +08:00
										 |  |  | 			.expectBody().isEmpty() | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Then switch to MockMvc server response assertions: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | [tabs] | 
					
						
							|  |  |  | ====== | 
					
						
							|  |  |  | Java:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | [source,java,indent=0,subs="verbatim,quotes",role="primary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	MockMvcWebTestClient.resultActionsFor(result) | 
					
						
							|  |  |  | 			.andExpect(model().attribute("integer", 3)) | 
					
						
							|  |  |  | 			.andExpect(model().attribute("string", "a string value")); | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Kotlin:: | 
					
						
							|  |  |  | + | 
					
						
							| 
									
										
										
										
											2020-09-01 15:56:57 +08:00
										 |  |  | [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | 
					
						
							|  |  |  | ---- | 
					
						
							|  |  |  | 	MockMvcWebTestClient.resultActionsFor(result) | 
					
						
							|  |  |  | 			.andExpect(model().attribute("integer", 3)) | 
					
						
							|  |  |  | 			.andExpect(model().attribute("string", "a string value")); | 
					
						
							|  |  |  | ---- | 
					
						
							| 
									
										
										
										
											2023-04-21 05:21:36 +08:00
										 |  |  | ====== |