WebFlux test support for server endpoints
Issue: SPR-14590
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.reactive.server.samples;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Tests with error status codes or error conditions.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ErrorTests {
|
||||
|
||||
private WebTestClient client;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.client = WebTestClient.bindToController(new TestController()).build();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void notFound() throws Exception {
|
||||
this.client.get().uri("/invalid")
|
||||
.exchange()
|
||||
.assertStatus().isNotFound();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverException() throws Exception {
|
||||
this.client.get().uri("/server-error")
|
||||
.exchange()
|
||||
.assertStatus().isInternalServerError();
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
@GetMapping("/server-error")
|
||||
void handleAndThrowException() {
|
||||
throw new IllegalStateException("server error");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.reactive.server.samples;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Tests with custom headers.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class HeaderTests {
|
||||
|
||||
private WebTestClient client;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.client = WebTestClient.bindToController(new TestController()).build();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void customHeader() throws Exception {
|
||||
this.client.get().uri("/header").header("h1", "ping")
|
||||
.exchange()
|
||||
.assertStatus().isOk()
|
||||
.assertHeader("h1").isEqualTo("ping-pong");
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
@GetMapping("header")
|
||||
ResponseEntity<Void> handleHeader(@RequestHeader("h1") String myHeader) {
|
||||
String value = myHeader + "-pong";
|
||||
return ResponseEntity.ok().header("h1", value).build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.reactive.server.samples;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.endsWith;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.springframework.http.MediaType.TEXT_EVENT_STREAM;
|
||||
|
||||
/**
|
||||
* Annotated controllers accepting and returning typed Objects.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ResponseEntityTests {
|
||||
|
||||
private WebTestClient client;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.client = WebTestClient.bindToController(new PersonController()).build();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void entity() throws Exception {
|
||||
this.client.get().uri("/persons/John")
|
||||
.exchange()
|
||||
.assertStatus().isOk()
|
||||
.assertHeaders().contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.assertEntity(Person.class).isEqualTo(new Person("John"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entityCollection() throws Exception {
|
||||
this.client.get().uri("/persons")
|
||||
.exchange()
|
||||
.assertStatus().isOk()
|
||||
.assertHeaders().contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.assertEntity(Person.class).collection()
|
||||
.hasSize(3)
|
||||
.contains(new Person("Jane"), new Person("Jason"), new Person("John"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entityStream() throws Exception {
|
||||
this.client.get().uri("/persons").accept(TEXT_EVENT_STREAM)
|
||||
.exchange()
|
||||
.assertStatus().isOk()
|
||||
.assertHeaders().contentType(TEXT_EVENT_STREAM)
|
||||
.assertEntity(Person.class).stepVerifier()
|
||||
.expectNext(new Person("N0"), new Person("N1"), new Person("N2"))
|
||||
.expectNextCount(4)
|
||||
.consumeNextWith(person -> assertThat(person.getName(), endsWith("7")))
|
||||
.thenCancel()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveEntity() throws Exception {
|
||||
this.client.post().uri("/persons")
|
||||
.exchange(Mono.just(new Person("John")), Person.class)
|
||||
.assertStatus().isCreated()
|
||||
.assertHeader("location").isEqualTo("/persons/John")
|
||||
.assertNoContent();
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/persons")
|
||||
static class PersonController {
|
||||
|
||||
@GetMapping("/{name}")
|
||||
Person getPerson(@PathVariable String name) {
|
||||
return new Person(name);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
Flux<Person> getPersons() {
|
||||
return Flux.just(new Person("Jane"), new Person("Jason"), new Person("John"));
|
||||
}
|
||||
|
||||
@GetMapping(produces = "text/event-stream")
|
||||
Flux<Person> getPersonStream() {
|
||||
return Flux.intervalMillis(100).onBackpressureBuffer(10).map(index -> new Person("N" + index));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
ResponseEntity<String> savePerson(@RequestBody Person person) {
|
||||
return ResponseEntity.created(URI.create("/persons/" + person.getName())).build();
|
||||
}
|
||||
}
|
||||
|
||||
static class Person {
|
||||
|
||||
private final String name;
|
||||
|
||||
@JsonCreator
|
||||
public Person(@JsonProperty("name") String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) return true;
|
||||
if (other == null || getClass() != other.getClass()) return false;
|
||||
Person person = (Person) other;
|
||||
return getName().equals(person.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getName().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Person[name='" + name + "']";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.reactive.server.samples.bind;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.reactive.config.EnableWebFlux;
|
||||
|
||||
/**
|
||||
* Binding to server infrastructure declared in a Spring ApplicationContext.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ApplicationContextTests {
|
||||
|
||||
private WebTestClient client;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(WebConfig.class);
|
||||
context.refresh();
|
||||
|
||||
this.client = WebTestClient.bindToApplicationContext(context).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
this.client.get().uri("/test")
|
||||
.exchange()
|
||||
.assertStatus().isOk()
|
||||
.assertEntity(String .class).isEqualTo("It works!");
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableWebFlux
|
||||
static class WebConfig {
|
||||
|
||||
@Bean
|
||||
public TestController controller() {
|
||||
return new TestController();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
@GetMapping("/test")
|
||||
public String handle() {
|
||||
return "It works!";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.reactive.server.samples.bind;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Bind to annotated controllers.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ControllerTests {
|
||||
|
||||
private WebTestClient client;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.client = WebTestClient.bindToController(new TestController()).build();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
this.client.get().uri("/test")
|
||||
.exchange()
|
||||
.assertStatus().isOk()
|
||||
.assertEntity(String .class).isEqualTo("It works!");
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
@GetMapping("/test")
|
||||
public String handle() {
|
||||
return "It works!";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.reactive.server.samples.bind;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.server.reactive.HttpHandler;
|
||||
import org.springframework.http.server.reactive.bootstrap.ReactorHttpServer;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
|
||||
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
|
||||
|
||||
/**
|
||||
* Bind to a running server, making actual requests over a socket.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class HttpServerTests {
|
||||
|
||||
private ReactorHttpServer server;
|
||||
|
||||
private WebTestClient client;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
HttpHandler httpHandler = RouterFunctions.toHttpHandler(
|
||||
route(GET("/test"), request ->
|
||||
ServerResponse.ok().body(Mono.just("It works!"), String.class)));
|
||||
|
||||
this.server = new ReactorHttpServer();
|
||||
this.server.setHandler(httpHandler);
|
||||
this.server.afterPropertiesSet();
|
||||
this.server.start();
|
||||
|
||||
this.client = WebTestClient.bindToServer()
|
||||
.baseUrl("http://localhost:" + this.server.getPort())
|
||||
.build();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
this.server.stop();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
this.client.get().uri("/test")
|
||||
.exchange()
|
||||
.assertStatus().isOk()
|
||||
.assertEntity(String .class).isEqualTo("It works!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.reactive.server.samples.bind;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
|
||||
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
|
||||
|
||||
/**
|
||||
* Bind to a {@link RouterFunction} and functional endpoints.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class RouterFunctionTests {
|
||||
|
||||
private WebTestClient testClient;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
RouterFunction<?> route = route(GET("/test"), request ->
|
||||
ServerResponse.ok().body(Mono.just("It works!"), String.class));
|
||||
|
||||
this.testClient = WebTestClient.bindToRouterFunction(route).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
this.testClient.get().uri("/test")
|
||||
.exchange()
|
||||
.assertStatus().isOk()
|
||||
.assertEntity(String .class).isEqualTo("It works!");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user