Add MockMvcTestClient
See gh-19647
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.context;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.ContextHierarchy;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
|
||||
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.context.AsyncControllerJavaConfigTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@WebAppConfiguration
|
||||
@ContextHierarchy(@ContextConfiguration(classes = AsyncControllerJavaConfigTests.WebConfig.class))
|
||||
public class AsyncControllerJavaConfigTests {
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext wac;
|
||||
|
||||
@Autowired
|
||||
private CallableProcessingInterceptor callableInterceptor;
|
||||
|
||||
private WebTestClient testClient;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.testClient = MockMvcTestClient.bindToApplicationContext(this.wac).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callableInterceptor() throws Exception {
|
||||
testClient.get().uri("/callable")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().json("{\"key\":\"value\"}");
|
||||
|
||||
Mockito.verify(this.callableInterceptor).beforeConcurrentHandling(any(), any());
|
||||
Mockito.verify(this.callableInterceptor).preProcess(any(), any());
|
||||
Mockito.verify(this.callableInterceptor).postProcess(any(), any(), any());
|
||||
Mockito.verify(this.callableInterceptor).afterCompletion(any(), any());
|
||||
Mockito.verifyNoMoreInteractions(this.callableInterceptor);
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
|
||||
configurer.registerCallableInterceptors(callableInterceptor());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CallableProcessingInterceptor callableInterceptor() {
|
||||
return Mockito.mock(CallableProcessingInterceptor.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AsyncController asyncController() {
|
||||
return new AsyncController();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class AsyncController {
|
||||
|
||||
@GetMapping("/callable")
|
||||
public Callable<Map<String, String>> getCallable() {
|
||||
return () -> Collections.singletonMap("key", "value");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.context;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.ContextHierarchy;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.test.web.servlet.samples.context.PersonController;
|
||||
import org.springframework.test.web.servlet.samples.context.PersonDao;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.context.JavaConfigTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@WebAppConfiguration("classpath:META-INF/web-resources")
|
||||
@ContextHierarchy({
|
||||
@ContextConfiguration(classes = JavaConfigTests.RootConfig.class),
|
||||
@ContextConfiguration(classes = JavaConfigTests.WebConfig.class)
|
||||
})
|
||||
public class JavaConfigTests {
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext wac;
|
||||
|
||||
@Autowired
|
||||
private PersonDao personDao;
|
||||
|
||||
@Autowired
|
||||
private PersonController personController;
|
||||
|
||||
private WebTestClient testClient;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.testClient = MockMvcTestClient.bindToApplicationContext(this.wac).build();
|
||||
given(this.personDao.getPerson(5L)).willReturn(new Person("Joe"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void person() {
|
||||
testClient.get().uri("/person/5")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().json("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tilesDefinitions() {
|
||||
testClient.get().uri("/")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEquals("Forwarded-Url", "/WEB-INF/layouts/standardLayout.jsp");
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class RootConfig {
|
||||
|
||||
@Bean
|
||||
public PersonDao personDao() {
|
||||
return Mockito.mock(PersonDao.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
@Autowired
|
||||
private RootConfig rootConfig;
|
||||
|
||||
@Bean
|
||||
public PersonController personController() {
|
||||
return new PersonController(this.rootConfig.personDao());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/").setViewName("home");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
|
||||
configurer.enable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureViewResolvers(ViewResolverRegistry registry) {
|
||||
registry.tiles();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TilesConfigurer tilesConfigurer() {
|
||||
TilesConfigurer configurer = new TilesConfigurer();
|
||||
configurer.setDefinitions("/WEB-INF/**/tiles.xml");
|
||||
return configurer;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.context;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.ContextHierarchy;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.handler;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.context.WebAppResourceTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
|
||||
@ContextHierarchy({
|
||||
@ContextConfiguration("../../context/root-context.xml"),
|
||||
@ContextConfiguration("../../context/servlet-context.xml")
|
||||
})
|
||||
public class WebAppResourceTests {
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext wac;
|
||||
|
||||
private WebTestClient testClient;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.testClient = MockMvcTestClient.bindToApplicationContext(this.wac).build();
|
||||
}
|
||||
|
||||
// TilesConfigurer: resources under "/WEB-INF/**/tiles.xml"
|
||||
|
||||
@Test
|
||||
public void tilesDefinitions() {
|
||||
testClient.get().uri("/")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEquals("Forwarded-Url", "/WEB-INF/layouts/standardLayout.jsp");
|
||||
}
|
||||
|
||||
// Resources served via <mvc:resources/>
|
||||
|
||||
@Test
|
||||
public void resourceRequest() {
|
||||
testClient.get().uri("/resources/Spring.js")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType("application/javascript")
|
||||
.expectBody(String.class).value(containsString("Spring={};"));
|
||||
}
|
||||
|
||||
// Forwarded to the "default" servlet via <mvc:default-servlet-handler/>
|
||||
|
||||
@Test
|
||||
public void resourcesViaDefaultServlet() throws Exception {
|
||||
EntityExchangeResult<Void> result = testClient.get().uri("/unknown/resource")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
MockMvcTestClient.resultActionsFor(result)
|
||||
.andExpect(handler().handlerType(DefaultServletHttpRequestHandler.class))
|
||||
.andExpect(forwardedUrl("default"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.context;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.ContextHierarchy;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.test.web.servlet.samples.context.PersonDao;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.context.XmlConfigTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
|
||||
@ContextHierarchy({
|
||||
@ContextConfiguration("../../context/root-context.xml"),
|
||||
@ContextConfiguration("../../context/servlet-context.xml")
|
||||
})
|
||||
public class XmlConfigTests {
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext wac;
|
||||
|
||||
@Autowired
|
||||
private PersonDao personDao;
|
||||
|
||||
private WebTestClient testClient;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.testClient = MockMvcTestClient.bindToApplicationContext(this.wac).build();
|
||||
given(this.personDao.getPerson(5L)).willReturn(new Person("Joe"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void person() {
|
||||
testClient.get().uri("/person/5")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().json("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tilesDefinitions() {
|
||||
testClient.get().uri("/")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEquals("Forwarded-Url", "/WEB-INF/layouts/standardLayout.jsp");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.AsyncTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class AsyncTests {
|
||||
|
||||
private final WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new AsyncController()).build();
|
||||
|
||||
|
||||
@Test
|
||||
public void callable() {
|
||||
this.testClient.get()
|
||||
.uri("/1?callable=true")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody().json("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void streaming() {
|
||||
this.testClient.get()
|
||||
.uri("/1?streaming=true")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).isEqualTo("name=Joe");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void streamingSlow() {
|
||||
this.testClient.get()
|
||||
.uri("/1?streamingSlow=true")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).isEqualTo("name=Joe&someBoolean=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void streamingJson() {
|
||||
this.testClient.get()
|
||||
.uri("/1?streamingJson=true")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody().json("{\"name\":\"Joe\",\"someDouble\":0.5}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deferredResult() {
|
||||
this.testClient.get()
|
||||
.uri("/1?deferredResult=true")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody().json("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deferredResultWithImmediateValue() throws Exception {
|
||||
this.testClient.get()
|
||||
.uri("/1?deferredResultWithImmediateValue=true")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody().json("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deferredResultWithDelayedError() throws Exception {
|
||||
this.testClient.get()
|
||||
.uri("/1?deferredResultWithDelayedError=true")
|
||||
.exchange()
|
||||
.expectStatus().is5xxServerError()
|
||||
.expectBody(String.class).isEqualTo("Delayed Error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listenableFuture() throws Exception {
|
||||
this.testClient.get()
|
||||
.uri("/1?listenableFuture=true")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody().json("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void completableFutureWithImmediateValue() throws Exception {
|
||||
this.testClient.get()
|
||||
.uri("/1?completableFutureWithImmediateValue=true")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody().json("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping(path = "/{id}", produces = "application/json")
|
||||
private static class AsyncController {
|
||||
|
||||
@RequestMapping(params = "callable")
|
||||
public Callable<Person> getCallable() {
|
||||
return () -> new Person("Joe");
|
||||
}
|
||||
|
||||
@RequestMapping(params = "streaming")
|
||||
public StreamingResponseBody getStreaming() {
|
||||
return os -> os.write("name=Joe".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@RequestMapping(params = "streamingSlow")
|
||||
public StreamingResponseBody getStreamingSlow() {
|
||||
return os -> {
|
||||
os.write("name=Joe".getBytes());
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
os.write("&someBoolean=true".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
/* no-op */
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@RequestMapping(params = "streamingJson")
|
||||
public ResponseEntity<StreamingResponseBody> getStreamingJson() {
|
||||
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON)
|
||||
.body(os -> os.write("{\"name\":\"Joe\",\"someDouble\":0.5}".getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
|
||||
@RequestMapping(params = "deferredResult")
|
||||
public DeferredResult<Person> getDeferredResult() {
|
||||
DeferredResult<Person> result = new DeferredResult<>();
|
||||
delay(100, () -> result.setResult(new Person("Joe")));
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(params = "deferredResultWithImmediateValue")
|
||||
public DeferredResult<Person> getDeferredResultWithImmediateValue() {
|
||||
DeferredResult<Person> result = new DeferredResult<>();
|
||||
result.setResult(new Person("Joe"));
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(params = "deferredResultWithDelayedError")
|
||||
public DeferredResult<Person> getDeferredResultWithDelayedError() {
|
||||
DeferredResult<Person> result = new DeferredResult<>();
|
||||
delay(100, () -> result.setErrorResult(new RuntimeException("Delayed Error")));
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(params = "listenableFuture")
|
||||
public ListenableFuture<Person> getListenableFuture() {
|
||||
ListenableFutureTask<Person> futureTask = new ListenableFutureTask<>(() -> new Person("Joe"));
|
||||
delay(100, futureTask);
|
||||
return futureTask;
|
||||
}
|
||||
|
||||
@RequestMapping(params = "completableFutureWithImmediateValue")
|
||||
public CompletableFuture<Person> getCompletableFutureWithImmediateValue() {
|
||||
CompletableFuture<Person> future = new CompletableFuture<>();
|
||||
future.complete(new Person("Joe"));
|
||||
return future;
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public String errorHandler(Exception ex) {
|
||||
return ex.getMessage();
|
||||
}
|
||||
|
||||
private void delay(long millis, Runnable task) {
|
||||
Mono.delay(Duration.ofMillis(millis)).doOnTerminate(task).subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.ExceptionHandlerTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
class ExceptionHandlerTests {
|
||||
|
||||
@Nested
|
||||
class MvcTests {
|
||||
|
||||
@Test
|
||||
void localExceptionHandlerMethod() {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new PersonController()).build();
|
||||
|
||||
client.get().uri("/person/Clyde")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEquals("Forwarded-Url", "errorView");
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalExceptionHandlerMethod() {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new PersonController())
|
||||
.controllerAdvice(new GlobalExceptionHandler())
|
||||
.build();
|
||||
|
||||
client.get().uri("/person/Bonnie")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEquals("Forwarded-Url", "globalErrorView");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class PersonController {
|
||||
|
||||
@GetMapping("/person/{name}")
|
||||
String show(@PathVariable String name) {
|
||||
if (name.equals("Clyde")) {
|
||||
throw new IllegalArgumentException("simulated exception");
|
||||
}
|
||||
else if (name.equals("Bonnie")) {
|
||||
throw new IllegalStateException("simulated exception");
|
||||
}
|
||||
return "person/show";
|
||||
}
|
||||
|
||||
@ExceptionHandler
|
||||
String handleException(IllegalArgumentException exception) {
|
||||
return "errorView";
|
||||
}
|
||||
}
|
||||
|
||||
@ControllerAdvice
|
||||
private static class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler
|
||||
String handleException(IllegalStateException exception) {
|
||||
return "globalErrorView";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Nested
|
||||
class RestTests {
|
||||
|
||||
@Test
|
||||
void noException() {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new RestPersonController())
|
||||
.controllerAdvice(new RestPersonControllerExceptionHandler())
|
||||
.build();
|
||||
|
||||
client.get().uri("/person/Yoda")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().jsonPath("$.name", "Yoda");
|
||||
}
|
||||
|
||||
@Test
|
||||
void localExceptionHandlerMethod() {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new RestPersonController())
|
||||
.controllerAdvice(new RestPersonControllerExceptionHandler())
|
||||
.build();
|
||||
|
||||
client.get().uri("/person/Luke")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().jsonPath("$.error", "local - IllegalArgumentException");
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalExceptionHandlerMethod() {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new RestPersonController())
|
||||
.controllerAdvice(new RestGlobalExceptionHandler())
|
||||
.build();
|
||||
|
||||
client.get().uri("/person/Leia")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().jsonPath("$.error", "global - IllegalArgumentException");
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalRestPersonControllerExceptionHandlerTakesPrecedenceOverGlobalExceptionHandler() {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new RestPersonController())
|
||||
.controllerAdvice(RestGlobalExceptionHandler.class, RestPersonControllerExceptionHandler.class)
|
||||
.build();
|
||||
|
||||
client.get().uri("/person/Leia")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().jsonPath("$.error", "globalPersonController - IllegalStateException");
|
||||
}
|
||||
|
||||
@Test
|
||||
void noHandlerFound() {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new RestPersonController())
|
||||
.controllerAdvice(RestGlobalExceptionHandler.class, RestPersonControllerExceptionHandler.class)
|
||||
.dispatcherServletCustomizer(servlet -> servlet.setThrowExceptionIfNoHandlerFound(true))
|
||||
.build();
|
||||
|
||||
client.get().uri("/bogus")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().jsonPath("$.error", "global - NoHandlerFoundException");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
private static class RestPersonController {
|
||||
|
||||
@GetMapping("/person/{name}")
|
||||
Person get(@PathVariable String name) {
|
||||
switch (name) {
|
||||
case "Luke":
|
||||
throw new IllegalArgumentException();
|
||||
case "Leia":
|
||||
throw new IllegalStateException();
|
||||
default:
|
||||
return new Person("Yoda");
|
||||
}
|
||||
}
|
||||
|
||||
@ExceptionHandler
|
||||
Error handleException(IllegalArgumentException exception) {
|
||||
return new Error("local - " + exception.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@RestControllerAdvice(assignableTypes = RestPersonController.class)
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
private static class RestPersonControllerExceptionHandler {
|
||||
|
||||
@ExceptionHandler
|
||||
Error handleException(Throwable exception) {
|
||||
return new Error("globalPersonController - " + exception.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@RestControllerAdvice
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
private static class RestGlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler
|
||||
Error handleException(Throwable exception) {
|
||||
return new Error( "global - " + exception.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
static class Person {
|
||||
|
||||
private final String name;
|
||||
|
||||
Person(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
static class Error {
|
||||
|
||||
private final String error;
|
||||
|
||||
Error(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncListener;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.filter.ShallowEtagHeaderFilter;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.flash;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.FilterTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class FilterTests {
|
||||
|
||||
@Test
|
||||
public void whenFiltersCompleteMvcProcessesRequest() throws Exception {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new PersonController())
|
||||
.filters(new ContinueFilter())
|
||||
.build();
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult = client.post().uri("/persons?name=Andy")
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectHeader().location("/person/1")
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().size(1))
|
||||
.andExpect(model().attributeExists("id"))
|
||||
.andExpect(flash().attributeCount(1))
|
||||
.andExpect(flash().attribute("message", "success!"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filtersProcessRequest() {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new PersonController())
|
||||
.filters(new ContinueFilter(), new RedirectFilter())
|
||||
.build();
|
||||
|
||||
client.post().uri("/persons?name=Andy")
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectHeader().location("/login");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterMappedBySuffix() {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new PersonController())
|
||||
.filter(new RedirectFilter(), "*.html")
|
||||
.build();
|
||||
|
||||
client.post().uri("/persons.html?name=Andy")
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectHeader().location("/login");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterWithExactMapping() {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new PersonController())
|
||||
.filter(new RedirectFilter(), "/p", "/persons")
|
||||
.build();
|
||||
|
||||
client.post().uri("/persons?name=Andy")
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectHeader().location("/login");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterSkipped() throws Exception {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new PersonController())
|
||||
.filter(new RedirectFilter(), "/p", "/person")
|
||||
.build();
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult =
|
||||
client.post().uri("/persons?name=Andy")
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectHeader().location("/person/1")
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().size(1))
|
||||
.andExpect(model().attributeExists("id"))
|
||||
.andExpect(flash().attributeCount(1))
|
||||
.andExpect(flash().attribute("message", "success!"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterWrapsRequestResponse() throws Exception {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new PersonController())
|
||||
.filter(new WrappingRequestResponseFilter())
|
||||
.build();
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult =
|
||||
client.post().uri("/user").exchange().expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().attribute("principal", WrappingRequestResponseFilter.PRINCIPAL_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterWrapsRequestResponseAndPerformsAsyncDispatch() {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new PersonController())
|
||||
.filters(new WrappingRequestResponseFilter(), new ShallowEtagHeaderFilter())
|
||||
.build();
|
||||
|
||||
client.get().uri("/persons/1")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentLength(53)
|
||||
.expectHeader().valueEquals("ETag", "\"0e37becb4f0c90709cb2e1efcc61eaa00\"")
|
||||
.expectBody().json("{\"name\":\"Lukas\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class PersonController {
|
||||
|
||||
@PostMapping(path="/persons")
|
||||
public String save(@Valid Person person, Errors errors, RedirectAttributes redirectAttrs) {
|
||||
if (errors.hasErrors()) {
|
||||
return "person/add";
|
||||
}
|
||||
redirectAttrs.addAttribute("id", "1");
|
||||
redirectAttrs.addFlashAttribute("message", "success!");
|
||||
return "redirect:/person/{id}";
|
||||
}
|
||||
|
||||
@PostMapping("/user")
|
||||
public ModelAndView user(Principal principal) {
|
||||
return new ModelAndView("user/view", "principal", principal.getName());
|
||||
}
|
||||
|
||||
@GetMapping("/forward")
|
||||
public String forward() {
|
||||
return "forward:/persons";
|
||||
}
|
||||
|
||||
@GetMapping("persons/{id}")
|
||||
@ResponseBody
|
||||
public CompletableFuture<Person> getPerson() {
|
||||
return CompletableFuture.completedFuture(new Person("Lukas"));
|
||||
}
|
||||
}
|
||||
|
||||
private class ContinueFilter extends OncePerRequestFilter {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request,
|
||||
HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private static class WrappingRequestResponseFilter extends OncePerRequestFilter {
|
||||
|
||||
public static final String PRINCIPAL_NAME = "WrapRequestResponseFilterPrincipal";
|
||||
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
|
||||
filterChain.doFilter(new HttpServletRequestWrapper(request) {
|
||||
|
||||
@Override
|
||||
public Principal getUserPrincipal() {
|
||||
return () -> PRINCIPAL_NAME;
|
||||
}
|
||||
|
||||
// Like Spring Security does in HttpServlet3RequestFactory..
|
||||
|
||||
@Override
|
||||
public AsyncContext getAsyncContext() {
|
||||
return super.getAsyncContext() != null ?
|
||||
new AsyncContextWrapper(super.getAsyncContext()) : null;
|
||||
}
|
||||
|
||||
}, new HttpServletResponseWrapper(response));
|
||||
}
|
||||
}
|
||||
|
||||
private class RedirectFilter extends OncePerRequestFilter {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
|
||||
response.sendRedirect("/login");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class AsyncContextWrapper implements AsyncContext {
|
||||
|
||||
private final AsyncContext delegate;
|
||||
|
||||
public AsyncContextWrapper(AsyncContext delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletRequest getRequest() {
|
||||
return this.delegate.getRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletResponse getResponse() {
|
||||
return this.delegate.getResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOriginalRequestAndResponse() {
|
||||
return this.delegate.hasOriginalRequestAndResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch() {
|
||||
this.delegate.dispatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(String path) {
|
||||
this.delegate.dispatch(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(ServletContext context, String path) {
|
||||
this.delegate.dispatch(context, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete() {
|
||||
this.delegate.complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Runnable run) {
|
||||
this.delegate.start(run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(AsyncListener listener) {
|
||||
this.delegate.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(AsyncListener listener, ServletRequest req, ServletResponse res) {
|
||||
this.delegate.addListener(listener, req, res);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException {
|
||||
return this.delegate.createListener(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimeout(long timeout) {
|
||||
this.delegate.setTimeout(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeout() {
|
||||
return this.delegate.getTimeout();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcConfigurerAdapter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.FrameworkExtensionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class FrameworkExtensionTests {
|
||||
|
||||
private final WebTestClient client =
|
||||
MockMvcTestClient.bindToController(new SampleController())
|
||||
.apply(defaultSetup())
|
||||
.build();
|
||||
|
||||
|
||||
@Test
|
||||
public void fooHeader() {
|
||||
this.client.get().uri("/")
|
||||
.header("Foo", "a=b")
|
||||
.exchange()
|
||||
.expectBody(String.class).isEqualTo("Foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void barHeader() {
|
||||
this.client.get().uri("/")
|
||||
.header("Bar", "a=b")
|
||||
.exchange()
|
||||
.expectBody(String.class).isEqualTo("Bar");
|
||||
}
|
||||
|
||||
private static TestMockMvcConfigurer defaultSetup() {
|
||||
return new TestMockMvcConfigurer();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test {@code MockMvcConfigurer}.
|
||||
*/
|
||||
private static class TestMockMvcConfigurer extends MockMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void afterConfigurerAdded(ConfigurableMockMvcBuilder<?> builder) {
|
||||
builder.alwaysExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPostProcessor beforeMockMvcCreated(ConfigurableMockMvcBuilder<?> builder,
|
||||
WebApplicationContext context) {
|
||||
return request -> {
|
||||
request.setUserPrincipal(mock(Principal.class));
|
||||
return request;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/")
|
||||
private static class SampleController {
|
||||
|
||||
@RequestMapping(headers = "Foo")
|
||||
@ResponseBody
|
||||
public String handleFoo(Principal principal) {
|
||||
Assert.notNull(principal, "Principal must not be null");
|
||||
return "Foo";
|
||||
}
|
||||
|
||||
@RequestMapping(headers = "Bar")
|
||||
@ResponseBody
|
||||
public String handleBar(Principal principal) {
|
||||
Assert.notNull(principal, "Principal must not be null");
|
||||
return "Bar";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.MultipartBodyBuilder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.MultipartControllerTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class MultipartControllerTests {
|
||||
|
||||
private final WebTestClient testClient = MockMvcTestClient.bindToController(new MultipartController()).build();
|
||||
|
||||
|
||||
@Test
|
||||
public void multipartRequestWithSingleFile() throws Exception {
|
||||
|
||||
byte[] fileContent = "bar".getBytes(StandardCharsets.UTF_8);
|
||||
Map<String, String> json = Collections.singletonMap("name", "yeeeah");
|
||||
|
||||
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
|
||||
bodyBuilder.part("file", fileContent).filename("orig");
|
||||
bodyBuilder.part("json", json, MediaType.APPLICATION_JSON);
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult = testClient.post().uri("/multipartfile")
|
||||
.bodyValue(bodyBuilder.build())
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().attribute("fileContent", fileContent))
|
||||
.andExpect(model().attribute("jsonContent", json));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartRequestWithSingleFileNotPresent() {
|
||||
testClient.post().uri("/multipartfile")
|
||||
.exchange()
|
||||
.expectStatus().isFound();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartRequestWithFileArray() throws Exception {
|
||||
byte[] fileContent = "bar".getBytes(StandardCharsets.UTF_8);
|
||||
Map<String, String> json = Collections.singletonMap("name", "yeeeah");
|
||||
|
||||
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
|
||||
bodyBuilder.part("file", fileContent).filename("orig");
|
||||
bodyBuilder.part("file", fileContent).filename("orig");
|
||||
bodyBuilder.part("json", json, MediaType.APPLICATION_JSON);
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult = testClient.post().uri("/multipartfilearray")
|
||||
.bodyValue(bodyBuilder.build())
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().attribute("fileContent", fileContent))
|
||||
.andExpect(model().attribute("jsonContent", json));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartRequestWithFileArrayNoMultipart() {
|
||||
testClient.post().uri("/multipartfilearray")
|
||||
.exchange()
|
||||
.expectStatus().isFound();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartRequestWithOptionalFile() throws Exception {
|
||||
byte[] fileContent = "bar".getBytes(StandardCharsets.UTF_8);
|
||||
Map<String, String> json = Collections.singletonMap("name", "yeeeah");
|
||||
|
||||
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
|
||||
bodyBuilder.part("file", fileContent).filename("orig");
|
||||
bodyBuilder.part("json", json, MediaType.APPLICATION_JSON);
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult = testClient.post().uri("/optionalfile")
|
||||
.bodyValue(bodyBuilder.build())
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().attribute("fileContent", fileContent))
|
||||
.andExpect(model().attribute("jsonContent", json));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartRequestWithOptionalFileNotPresent() throws Exception {
|
||||
Map<String, String> json = Collections.singletonMap("name", "yeeeah");
|
||||
|
||||
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
|
||||
bodyBuilder.part("json", json, MediaType.APPLICATION_JSON);
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult = testClient.post().uri("/optionalfile")
|
||||
.bodyValue(bodyBuilder.build())
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().attributeDoesNotExist("fileContent"))
|
||||
.andExpect(model().attribute("jsonContent", json));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartRequestWithOptionalFileArray() throws Exception {
|
||||
byte[] fileContent = "bar".getBytes(StandardCharsets.UTF_8);
|
||||
Map<String, String> json = Collections.singletonMap("name", "yeeeah");
|
||||
|
||||
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
|
||||
bodyBuilder.part("file", fileContent).filename("orig");
|
||||
bodyBuilder.part("file", fileContent).filename("orig");
|
||||
bodyBuilder.part("json", json, MediaType.APPLICATION_JSON);
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult = testClient.post().uri("/optionalfilearray")
|
||||
.bodyValue(bodyBuilder.build())
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().attribute("fileContent", fileContent))
|
||||
.andExpect(model().attribute("jsonContent", json));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartRequestWithOptionalFileArrayNotPresent() throws Exception {
|
||||
Map<String, String> json = Collections.singletonMap("name", "yeeeah");
|
||||
|
||||
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
|
||||
bodyBuilder.part("json", json, MediaType.APPLICATION_JSON);
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult = testClient.post().uri("/optionalfilearray")
|
||||
.bodyValue(bodyBuilder.build())
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().attributeDoesNotExist("fileContent"))
|
||||
.andExpect(model().attribute("jsonContent", json));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartRequestWithOptionalFileList() throws Exception {
|
||||
byte[] fileContent = "bar".getBytes(StandardCharsets.UTF_8);
|
||||
Map<String, String> json = Collections.singletonMap("name", "yeeeah");
|
||||
|
||||
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
|
||||
bodyBuilder.part("file", fileContent).filename("orig");
|
||||
bodyBuilder.part("file", fileContent).filename("orig");
|
||||
bodyBuilder.part("json", json, MediaType.APPLICATION_JSON);
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult = testClient.post().uri("/optionalfilelist")
|
||||
.bodyValue(bodyBuilder.build())
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().attribute("fileContent", fileContent))
|
||||
.andExpect(model().attribute("jsonContent", json));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartRequestWithOptionalFileListNotPresent() throws Exception {
|
||||
Map<String, String> json = Collections.singletonMap("name", "yeeeah");
|
||||
|
||||
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
|
||||
bodyBuilder.part("json", json, MediaType.APPLICATION_JSON);
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult = testClient.post().uri("/optionalfilelist")
|
||||
.bodyValue(bodyBuilder.build())
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().attributeDoesNotExist("fileContent"))
|
||||
.andExpect(model().attribute("jsonContent", json));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartRequestWithServletParts() throws Exception {
|
||||
byte[] fileContent = "bar".getBytes(StandardCharsets.UTF_8);
|
||||
Map<String, String> json = Collections.singletonMap("name", "yeeeah");
|
||||
|
||||
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
|
||||
bodyBuilder.part("file", fileContent).filename("orig");
|
||||
bodyBuilder.part("json", json, MediaType.APPLICATION_JSON);
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult = testClient.post().uri("/multipartfile")
|
||||
.bodyValue(bodyBuilder.build())
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().attribute("fileContent", fileContent))
|
||||
.andExpect(model().attribute("jsonContent", json));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartRequestWrapped() throws Exception {
|
||||
Map<String, String> json = Collections.singletonMap("name", "yeeeah");
|
||||
|
||||
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
|
||||
bodyBuilder.part("json", json, MediaType.APPLICATION_JSON);
|
||||
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new MultipartController())
|
||||
.filter(new RequestWrappingFilter())
|
||||
.build();
|
||||
|
||||
EntityExchangeResult<Void> exchangeResult = client.post().uri("/multipartfile")
|
||||
.bodyValue(bodyBuilder.build())
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().attribute("jsonContent", json));
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class MultipartController {
|
||||
|
||||
@RequestMapping(value = "/multipartfile", method = RequestMethod.POST)
|
||||
public String processMultipartFile(@RequestParam(required = false) MultipartFile file,
|
||||
@RequestPart(required = false) Map<String, String> json, Model model) throws IOException {
|
||||
|
||||
if (file != null) {
|
||||
model.addAttribute("fileContent", file.getBytes());
|
||||
}
|
||||
if (json != null) {
|
||||
model.addAttribute("jsonContent", json);
|
||||
}
|
||||
|
||||
return "redirect:/index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/multipartfilearray", method = RequestMethod.POST)
|
||||
public String processMultipartFileArray(@RequestParam(required = false) MultipartFile[] file,
|
||||
@RequestPart(required = false) Map<String, String> json, Model model) throws IOException {
|
||||
|
||||
if (file != null && file.length > 0) {
|
||||
byte[] content = file[0].getBytes();
|
||||
assertThat(file[1].getBytes()).isEqualTo(content);
|
||||
model.addAttribute("fileContent", content);
|
||||
}
|
||||
if (json != null) {
|
||||
model.addAttribute("jsonContent", json);
|
||||
}
|
||||
|
||||
return "redirect:/index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/multipartfilelist", method = RequestMethod.POST)
|
||||
public String processMultipartFileList(@RequestParam(required = false) List<MultipartFile> file,
|
||||
@RequestPart(required = false) Map<String, String> json, Model model) throws IOException {
|
||||
|
||||
if (file != null && !file.isEmpty()) {
|
||||
byte[] content = file.get(0).getBytes();
|
||||
assertThat(file.get(1).getBytes()).isEqualTo(content);
|
||||
model.addAttribute("fileContent", content);
|
||||
}
|
||||
if (json != null) {
|
||||
model.addAttribute("jsonContent", json);
|
||||
}
|
||||
|
||||
return "redirect:/index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/optionalfile", method = RequestMethod.POST)
|
||||
public String processOptionalFile(@RequestParam Optional<MultipartFile> file,
|
||||
@RequestPart Map<String, String> json, Model model) throws IOException {
|
||||
|
||||
if (file.isPresent()) {
|
||||
model.addAttribute("fileContent", file.get().getBytes());
|
||||
}
|
||||
model.addAttribute("jsonContent", json);
|
||||
|
||||
return "redirect:/index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/optionalfilearray", method = RequestMethod.POST)
|
||||
public String processOptionalFileArray(@RequestParam Optional<MultipartFile[]> file,
|
||||
@RequestPart Map<String, String> json, Model model) throws IOException {
|
||||
|
||||
if (file.isPresent()) {
|
||||
byte[] content = file.get()[0].getBytes();
|
||||
assertThat(file.get()[1].getBytes()).isEqualTo(content);
|
||||
model.addAttribute("fileContent", content);
|
||||
}
|
||||
model.addAttribute("jsonContent", json);
|
||||
|
||||
return "redirect:/index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/optionalfilelist", method = RequestMethod.POST)
|
||||
public String processOptionalFileList(@RequestParam Optional<List<MultipartFile>> file,
|
||||
@RequestPart Map<String, String> json, Model model) throws IOException {
|
||||
|
||||
if (file.isPresent()) {
|
||||
byte[] content = file.get().get(0).getBytes();
|
||||
assertThat(file.get().get(1).getBytes()).isEqualTo(content);
|
||||
model.addAttribute("fileContent", content);
|
||||
}
|
||||
model.addAttribute("jsonContent", json);
|
||||
|
||||
return "redirect:/index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/part", method = RequestMethod.POST)
|
||||
public String processPart(@RequestParam Part part,
|
||||
@RequestPart Map<String, String> json, Model model) throws IOException {
|
||||
|
||||
model.addAttribute("fileContent", part.getInputStream());
|
||||
model.addAttribute("jsonContent", json);
|
||||
|
||||
return "redirect:/index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/json", method = RequestMethod.POST)
|
||||
public String processMultipart(@RequestPart Map<String, String> json, Model model) {
|
||||
model.addAttribute("json", json);
|
||||
return "redirect:/index";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class RequestWrappingFilter extends OncePerRequestFilter {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws IOException, ServletException {
|
||||
|
||||
request = new HttpServletRequestWrapper(request);
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.springframework.http.MediaType.TEXT_EVENT_STREAM;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.ReactiveReturnTypeTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ReactiveReturnTypeTests {
|
||||
|
||||
@Test
|
||||
public void sseWithFlux() {
|
||||
|
||||
WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new ReactiveController()).build();
|
||||
|
||||
Flux<String> bodyFlux = testClient.get().uri("/spr16869")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentTypeCompatibleWith(TEXT_EVENT_STREAM)
|
||||
.returnResult(String.class)
|
||||
.getResponseBody();
|
||||
|
||||
StepVerifier.create(bodyFlux)
|
||||
.expectNext("event0")
|
||||
.expectNext("event1")
|
||||
.expectNext("event2")
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
static class ReactiveController {
|
||||
|
||||
@GetMapping(path = "/spr16869", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
Flux<String> sseFlux() {
|
||||
return Flux.interval(Duration.ofSeconds(1)).take(3)
|
||||
.map(aLong -> String.format("event%d", aLong));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.Errors;
|
||||
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.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.flash;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.RedirectTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class RedirectTests {
|
||||
|
||||
private final WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new PersonController()).build();
|
||||
|
||||
|
||||
@Test
|
||||
public void save() throws Exception {
|
||||
EntityExchangeResult<Void> exchangeResult =
|
||||
testClient.post().uri("/persons?name=Andy")
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectHeader().location("/persons/Joe")
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(exchangeResult)
|
||||
.andExpect(model().size(1))
|
||||
.andExpect(model().attributeExists("name"))
|
||||
.andExpect(flash().attributeCount(1))
|
||||
.andExpect(flash().attribute("message", "success!"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveSpecial() throws Exception {
|
||||
EntityExchangeResult<Void> result =
|
||||
testClient.post().uri("/people?name=Andy")
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectHeader().location("/persons/Joe")
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(result)
|
||||
.andExpect(model().size(1))
|
||||
.andExpect(model().attributeExists("name"))
|
||||
.andExpect(flash().attributeCount(1))
|
||||
.andExpect(flash().attribute("message", "success!"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveWithErrors() throws Exception {
|
||||
EntityExchangeResult<Void> result =
|
||||
testClient.post().uri("/persons").exchange().expectStatus().isOk().expectBody().isEmpty();
|
||||
|
||||
MockMvcTestClient.resultActionsFor(result)
|
||||
.andExpect(forwardedUrl("persons/add"))
|
||||
.andExpect(model().size(1))
|
||||
.andExpect(model().attributeExists("person"))
|
||||
.andExpect(flash().attributeCount(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveSpecialWithErrors() throws Exception {
|
||||
EntityExchangeResult<Void> result =
|
||||
testClient.post().uri("/people").exchange().expectStatus().isOk().expectBody().isEmpty();
|
||||
|
||||
MockMvcTestClient.resultActionsFor(result)
|
||||
.andExpect(forwardedUrl("persons/add"))
|
||||
.andExpect(model().size(1))
|
||||
.andExpect(model().attributeExists("person"))
|
||||
.andExpect(flash().attributeCount(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPerson() throws Exception {
|
||||
EntityExchangeResult<Void> result =
|
||||
MockMvcTestClient.bindToController(new PersonController())
|
||||
.defaultRequest(get("/").flashAttr("message", "success!"))
|
||||
.build()
|
||||
.get().uri("/persons/Joe")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(result)
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(forwardedUrl("persons/index"))
|
||||
.andExpect(model().size(2))
|
||||
.andExpect(model().attribute("person", new Person("Joe")))
|
||||
.andExpect(model().attribute("message", "success!"))
|
||||
.andExpect(flash().attributeCount(0));
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class PersonController {
|
||||
|
||||
@GetMapping("/persons/{name}")
|
||||
public String getPerson(@PathVariable String name, Model model) {
|
||||
model.addAttribute(new Person(name));
|
||||
return "persons/index";
|
||||
}
|
||||
|
||||
@PostMapping("/persons")
|
||||
public String save(@Valid Person person, Errors errors, RedirectAttributes redirectAttrs) {
|
||||
if (errors.hasErrors()) {
|
||||
return "persons/add";
|
||||
}
|
||||
redirectAttrs.addAttribute("name", "Joe");
|
||||
redirectAttrs.addFlashAttribute("message", "success!");
|
||||
return "redirect:/persons/{name}";
|
||||
}
|
||||
|
||||
@PostMapping("/people")
|
||||
public Object saveSpecial(@Valid Person person, Errors errors, RedirectAttributes redirectAttrs) {
|
||||
if (errors.hasErrors()) {
|
||||
return "persons/add";
|
||||
}
|
||||
redirectAttrs.addAttribute("name", "Joe");
|
||||
redirectAttrs.addFlashAttribute("message", "success!");
|
||||
return new StringBuilder("redirect:").append("/persons").append("/{name}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.RequestParameterTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class RequestParameterTests {
|
||||
|
||||
@Test
|
||||
public void queryParameter() {
|
||||
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new PersonController()).build();
|
||||
|
||||
client.get().uri("/search?name=George")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody().jsonPath("$.name", "George");
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private class PersonController {
|
||||
|
||||
@RequestMapping(value="/search")
|
||||
@ResponseBody
|
||||
public Person get(@RequestParam String name) {
|
||||
Person person = new Person(name);
|
||||
return person;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.ResponseBodyTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ResponseBodyTests {
|
||||
|
||||
@Test
|
||||
void json() {
|
||||
MockMvcTestClient.bindToController(new PersonController()).build()
|
||||
.get()
|
||||
.uri("/person/Lee")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody()
|
||||
.jsonPath("$.name").isEqualTo("Lee")
|
||||
.jsonPath("$.age").isEqualTo(42)
|
||||
.jsonPath("$.age").value(equalTo(42))
|
||||
.jsonPath("$.age").value(equalTo(42.0f), Float.class);
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
private static class PersonController {
|
||||
|
||||
@GetMapping("/person/{name}")
|
||||
public Person get(@PathVariable String name) {
|
||||
Person person = new Person(name);
|
||||
person.setAge(42);
|
||||
return person;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Person {
|
||||
|
||||
@NotNull
|
||||
private final String name;
|
||||
|
||||
private int age;
|
||||
|
||||
public Person(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return this.age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.accept.FixedContentNegotiationStrategy;
|
||||
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.servlet.View;
|
||||
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
|
||||
import org.springframework.web.servlet.view.InternalResourceViewResolver;
|
||||
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
|
||||
import org.springframework.web.servlet.view.xml.MarshallingView;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasProperty;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.RequestParameterTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
class ViewResolutionTests {
|
||||
|
||||
@Test
|
||||
void jspOnly() throws Exception {
|
||||
WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new PersonController())
|
||||
.viewResolvers(new InternalResourceViewResolver("/WEB-INF/", ".jsp"))
|
||||
.build();
|
||||
|
||||
EntityExchangeResult<Void> result = testClient.get().uri("/person/Corea")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(result)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(model().size(1))
|
||||
.andExpect(model().attributeExists("person"))
|
||||
.andExpect(forwardedUrl("/WEB-INF/person/show.jsp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsonOnly() {
|
||||
WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new PersonController())
|
||||
.singleView(new MappingJackson2JsonView())
|
||||
.build();
|
||||
|
||||
testClient.get().uri("/person/Corea")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)
|
||||
.expectBody().jsonPath("$.person.name", "Corea");
|
||||
}
|
||||
|
||||
@Test
|
||||
void xmlOnly() {
|
||||
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
|
||||
marshaller.setClassesToBeBound(Person.class);
|
||||
|
||||
WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new PersonController())
|
||||
.singleView(new MarshallingView(marshaller))
|
||||
.build();
|
||||
|
||||
testClient.get().uri("/person/Corea")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_XML)
|
||||
.expectBody().xpath("/person/name/text()").isEqualTo("Corea");
|
||||
}
|
||||
|
||||
@Test
|
||||
void contentNegotiation() throws Exception {
|
||||
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
|
||||
marshaller.setClassesToBeBound(Person.class);
|
||||
|
||||
List<View> viewList = new ArrayList<>();
|
||||
viewList.add(new MappingJackson2JsonView());
|
||||
viewList.add(new MarshallingView(marshaller));
|
||||
|
||||
ContentNegotiationManager manager = new ContentNegotiationManager(
|
||||
new HeaderContentNegotiationStrategy(), new FixedContentNegotiationStrategy(MediaType.TEXT_HTML));
|
||||
|
||||
ContentNegotiatingViewResolver cnViewResolver = new ContentNegotiatingViewResolver();
|
||||
cnViewResolver.setDefaultViews(viewList);
|
||||
cnViewResolver.setContentNegotiationManager(manager);
|
||||
cnViewResolver.afterPropertiesSet();
|
||||
|
||||
WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new PersonController())
|
||||
.viewResolvers(cnViewResolver, new InternalResourceViewResolver())
|
||||
.build();
|
||||
|
||||
EntityExchangeResult<Void> result = testClient.get().uri("/person/Corea")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(result)
|
||||
.andExpect(model().size(1))
|
||||
.andExpect(model().attributeExists("person"))
|
||||
.andExpect(forwardedUrl("person/show"));
|
||||
|
||||
testClient.get().uri("/person/Corea")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)
|
||||
.expectBody().jsonPath("$.person.name", "Corea");
|
||||
|
||||
testClient.get().uri("/person/Corea")
|
||||
.accept(MediaType.APPLICATION_XML)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_XML)
|
||||
.expectBody().xpath("/person/name/text()").isEqualTo("Corea");
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultViewResolver() throws Exception {
|
||||
WebTestClient client = MockMvcTestClient.bindToController(new PersonController()).build();
|
||||
|
||||
EntityExchangeResult<Void> result = client.get().uri("/person/Corea")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
// Further assertions on the server response
|
||||
MockMvcTestClient.resultActionsFor(result)
|
||||
.andExpect(model().attribute("person", hasProperty("name", equalTo("Corea"))))
|
||||
.andExpect(forwardedUrl("person/show")); // InternalResourceViewResolver
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class PersonController {
|
||||
|
||||
@GetMapping("/person/{name}")
|
||||
String show(@PathVariable String name, Model model) {
|
||||
Person person = new Person(name);
|
||||
model.addAttribute(person);
|
||||
return "person/show";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resulthandlers;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resulthandlers.PrintingResultHandlerSmokeTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@Disabled
|
||||
public class PrintingResultHandlerSmokeTests {
|
||||
|
||||
private final WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new SimpleController()).build();
|
||||
|
||||
|
||||
// Not intended to be executed with the build.
|
||||
// Comment out class-level @Disabled to see the output.
|
||||
|
||||
@Test
|
||||
public void printViaConsumer() {
|
||||
testClient.post().uri("/")
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.bodyValue("Hello Request".getBytes(StandardCharsets.UTF_8))
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class)
|
||||
.consumeWith(System.out::println);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnResultAndPrint() {
|
||||
EntityExchangeResult<String> result = testClient.post().uri("/")
|
||||
.contentType(MediaType.TEXT_PLAIN)
|
||||
.bodyValue("Hello Request".getBytes(StandardCharsets.UTF_8))
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class)
|
||||
.returnResult();
|
||||
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
private static class SimpleController {
|
||||
|
||||
@PostMapping("/")
|
||||
public String hello(HttpServletResponse response) {
|
||||
response.addCookie(new Cookie("enigma", "42"));
|
||||
return "Hello Response";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.ContentAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ContentAssertionTests {
|
||||
|
||||
private final WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new SimpleController()).build();
|
||||
|
||||
@Test
|
||||
public void testContentType() {
|
||||
testClient.get().uri("/handle").accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.valueOf("text/plain;charset=ISO-8859-1"))
|
||||
.expectHeader().contentType("text/plain;charset=ISO-8859-1")
|
||||
.expectHeader().contentTypeCompatibleWith("text/plain")
|
||||
.expectHeader().contentTypeCompatibleWith(MediaType.TEXT_PLAIN);
|
||||
|
||||
testClient.get().uri("/handleUtf8")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.valueOf("text/plain;charset=UTF-8"))
|
||||
.expectHeader().contentType("text/plain;charset=UTF-8")
|
||||
.expectHeader().contentTypeCompatibleWith("text/plain")
|
||||
.expectHeader().contentTypeCompatibleWith(MediaType.TEXT_PLAIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContentAsString() {
|
||||
|
||||
testClient.get().uri("/handle").accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).isEqualTo("Hello world!");
|
||||
|
||||
testClient.get().uri("/handleUtf8").accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).isEqualTo("\u3053\u3093\u306b\u3061\u306f\u4e16\u754c\uff01");
|
||||
|
||||
// Hamcrest matchers...
|
||||
testClient.get().uri("/handle").accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).value(equalTo("Hello world!"));
|
||||
testClient.get().uri("/handleUtf8")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).value(equalTo("\u3053\u3093\u306b\u3061\u306f\u4e16\u754c\uff01"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContentAsBytes() {
|
||||
|
||||
testClient.get().uri("/handle").accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(byte[].class).isEqualTo(
|
||||
"Hello world!".getBytes(StandardCharsets.ISO_8859_1));
|
||||
|
||||
testClient.get().uri("/handleUtf8")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(byte[].class).isEqualTo(
|
||||
"\u3053\u3093\u306b\u3061\u306f\u4e16\u754c\uff01".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContentStringMatcher() {
|
||||
testClient.get().uri("/handle").accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).value(containsString("world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCharacterEncoding() {
|
||||
|
||||
testClient.get().uri("/handle").accept(MediaType.TEXT_PLAIN)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType("text/plain;charset=ISO-8859-1")
|
||||
.expectBody(String.class).value(containsString("world"));
|
||||
|
||||
testClient.get().uri("/handleUtf8")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType("text/plain;charset=UTF-8")
|
||||
.expectBody(byte[].class)
|
||||
.isEqualTo("\u3053\u3093\u306b\u3061\u306f\u4e16\u754c\uff01".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class SimpleController {
|
||||
|
||||
@RequestMapping(value="/handle", produces="text/plain")
|
||||
@ResponseBody
|
||||
public String handle() {
|
||||
return "Hello world!";
|
||||
}
|
||||
|
||||
@RequestMapping(value="/handleUtf8", produces="text/plain;charset=UTF-8")
|
||||
@ResponseBody
|
||||
public String handleWithCharset() {
|
||||
return "\u3053\u3093\u306b\u3061\u306f\u4e16\u754c\uff01"; // "Hello world! (Japanese)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
|
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.CookieAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class CookieAssertionTests {
|
||||
|
||||
private static final String COOKIE_NAME = CookieLocaleResolver.DEFAULT_COOKIE_NAME;
|
||||
|
||||
private WebTestClient client;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
|
||||
localeResolver.setCookieDomain("domain");
|
||||
localeResolver.setCookieHttpOnly(true);
|
||||
|
||||
client = MockMvcTestClient.bindToController(new SimpleController())
|
||||
.interceptors(new LocaleChangeInterceptor())
|
||||
.localeResolver(localeResolver)
|
||||
.alwaysExpect(status().isOk())
|
||||
.configureClient()
|
||||
.baseUrl("/?locale=en_US")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExists() {
|
||||
client.get().uri("/").exchange().expectCookie().exists(COOKIE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotExists() {
|
||||
client.get().uri("/").exchange().expectCookie().doesNotExist("unknownCookie");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualTo() {
|
||||
client.get().uri("/").exchange().expectCookie().valueEquals(COOKIE_NAME, "en-US");
|
||||
client.get().uri("/").exchange().expectCookie().value(COOKIE_NAME, equalTo("en-US"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatcher() {
|
||||
client.get().uri("/").exchange().expectCookie().value(COOKIE_NAME, startsWith("en-US"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaxAge() {
|
||||
client.get().uri("/").exchange().expectCookie().maxAge(COOKIE_NAME, Duration.ofSeconds(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomain() {
|
||||
client.get().uri("/").exchange().expectCookie().domain(COOKIE_NAME, "domain");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPath() {
|
||||
client.get().uri("/").exchange().expectCookie().path(COOKIE_NAME, "/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecured() {
|
||||
client.get().uri("/").exchange().expectCookie().secure(COOKIE_NAME, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpOnly() {
|
||||
client.get().uri("/").exchange().expectCookie().httpOnly(COOKIE_NAME, true);
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class SimpleController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public String home() {
|
||||
return "home";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.hamcrest.Matchers.closeTo;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.flash;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.FlashAttributeAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class FlashAttributeAssertionTests {
|
||||
|
||||
private final WebTestClient client =
|
||||
MockMvcTestClient.bindToController(new PersonController())
|
||||
.alwaysExpect(status().isFound())
|
||||
.alwaysExpect(flash().attributeCount(3))
|
||||
.build();
|
||||
|
||||
|
||||
@Test
|
||||
void attributeCountWithWrongCount() {
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> performRequest().andExpect(flash().attributeCount(1)))
|
||||
.withMessage("FlashMap size expected:<1> but was:<3>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void attributeExists() throws Exception {
|
||||
performRequest().andExpect(flash().attributeExists("one", "two", "three"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void attributeEqualTo() throws Exception {
|
||||
performRequest()
|
||||
.andExpect(flash().attribute("one", "1"))
|
||||
.andExpect(flash().attribute("two", 2.222))
|
||||
.andExpect(flash().attribute("three", new URL("https://example.com")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void attributeMatchers() throws Exception {
|
||||
performRequest()
|
||||
.andExpect(flash().attribute("one", containsString("1")))
|
||||
.andExpect(flash().attribute("two", closeTo(2, 0.5)))
|
||||
.andExpect(flash().attribute("three", notNullValue()))
|
||||
.andExpect(flash().attribute("one", equalTo("1")))
|
||||
.andExpect(flash().attribute("two", equalTo(2.222)))
|
||||
.andExpect(flash().attribute("three", equalTo(new URL("https://example.com"))));
|
||||
}
|
||||
|
||||
private ResultActions performRequest() {
|
||||
EntityExchangeResult<Void> result = client.post().uri("/persons").exchange().expectBody().isEmpty();
|
||||
return MockMvcTestClient.resultActionsFor(result);
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class PersonController {
|
||||
|
||||
@PostMapping("/persons")
|
||||
String save(RedirectAttributes redirectAttrs) throws Exception {
|
||||
redirectAttrs.addFlashAttribute("one", "1");
|
||||
redirectAttrs.addFlashAttribute("two", 2.222);
|
||||
redirectAttrs.addFlashAttribute("three", new URL("https://example.com"));
|
||||
return "redirect:/person/1";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.handler;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder.on;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.HandlerAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class HandlerAssertionTests {
|
||||
|
||||
private final WebTestClient client =
|
||||
MockMvcTestClient.bindToController(new SimpleController())
|
||||
.alwaysExpect(status().isOk())
|
||||
.build();
|
||||
|
||||
|
||||
@Test
|
||||
public void handlerType() throws Exception {
|
||||
performRequest().andExpect(handler().handlerType(SimpleController.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodCallOnNonMock() {
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> performRequest().andExpect(handler().methodCall("bogus")))
|
||||
.withMessageContaining("The supplied object [bogus] is not an instance of")
|
||||
.withMessageContaining(MvcUriComponentsBuilder.MethodInvocationInfo.class.getName())
|
||||
.withMessageContaining("Ensure that you invoke the handler method via MvcUriComponentsBuilder.on()");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodCall() throws Exception {
|
||||
performRequest().andExpect(handler().methodCall(on(SimpleController.class).handle()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodName() throws Exception {
|
||||
performRequest().andExpect(handler().methodName("handle"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodNameMatchers() throws Exception {
|
||||
performRequest()
|
||||
.andExpect(handler().methodName(equalTo("handle")))
|
||||
.andExpect(handler().methodName(is(not("save"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void method() throws Exception {
|
||||
Method method = SimpleController.class.getMethod("handle");
|
||||
performRequest().andExpect(handler().method(method));
|
||||
}
|
||||
|
||||
private ResultActions performRequest() {
|
||||
EntityExchangeResult<Void> result = client.get().uri("/").exchange().expectBody().isEmpty();
|
||||
return MockMvcTestClient.resultActionsFor(result);
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
static class SimpleController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public ResponseEntity<Void> handle() {
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.springframework.http.HttpHeaders.IF_MODIFIED_SINCE;
|
||||
import static org.springframework.http.HttpHeaders.LAST_MODIFIED;
|
||||
import static org.springframework.http.HttpHeaders.VARY;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.HeaderAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class HeaderAssertionTests {
|
||||
|
||||
private static final String ERROR_MESSAGE = "Should have thrown an AssertionError";
|
||||
|
||||
|
||||
private String now;
|
||||
|
||||
private String minuteAgo;
|
||||
|
||||
private WebTestClient testClient;
|
||||
|
||||
private final long currentTime = System.currentTimeMillis();
|
||||
|
||||
private SimpleDateFormat dateFormat;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
|
||||
this.dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
this.now = dateFormat.format(new Date(this.currentTime));
|
||||
this.minuteAgo = dateFormat.format(new Date(this.currentTime - (1000 * 60)));
|
||||
|
||||
PersonController controller = new PersonController();
|
||||
controller.setStubTimestamp(this.currentTime);
|
||||
this.testClient = MockMvcTestClient.bindToController(controller).build();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void stringWithCorrectResponseHeaderValue() {
|
||||
testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEquals(LAST_MODIFIED, now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringWithMatcherAndCorrectResponseHeaderValue() {
|
||||
testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().value(LAST_MODIFIED, equalTo(now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiStringHeaderValue() {
|
||||
testClient.get().uri("/persons/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEquals(VARY, "foo", "bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiStringHeaderValueWithMatchers() {
|
||||
testClient.get().uri("/persons/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().values(VARY, hasItems(containsString("foo"), startsWith("bar")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dateValueWithCorrectResponseHeaderValue() {
|
||||
testClient.get().uri("/persons/1")
|
||||
.header(IF_MODIFIED_SINCE, minuteAgo)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEqualsDate(LAST_MODIFIED, this.currentTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longValueWithCorrectResponseHeaderValue() {
|
||||
testClient.get().uri("/persons/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEquals("X-Rate-Limiting", 42);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringWithMissingResponseHeader() {
|
||||
testClient.get().uri("/persons/1")
|
||||
.header(IF_MODIFIED_SINCE, now)
|
||||
.exchange()
|
||||
.expectStatus().isNotModified()
|
||||
.expectHeader().valueEquals("X-Custom-Header");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringWithMatcherAndMissingResponseHeader() {
|
||||
testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, now)
|
||||
.exchange()
|
||||
.expectStatus().isNotModified()
|
||||
.expectHeader().value("X-Custom-Header", nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longValueWithMissingResponseHeader() {
|
||||
try {
|
||||
testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, now)
|
||||
.exchange()
|
||||
.expectStatus().isNotModified()
|
||||
.expectHeader().valueEquals("X-Custom-Header", 99L);
|
||||
|
||||
fail(ERROR_MESSAGE);
|
||||
}
|
||||
catch (AssertionError err) {
|
||||
if (ERROR_MESSAGE.equals(err.getMessage())) {
|
||||
throw err;
|
||||
}
|
||||
assertThat(err.getMessage()).startsWith("Response does not contain header 'X-Custom-Header'");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exists() {
|
||||
testClient.get().uri("/persons/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().exists(LAST_MODIFIED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void existsFail() {
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
|
||||
testClient.get().uri("/persons/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().exists("X-Custom-Header"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotExist() {
|
||||
testClient.get().uri("/persons/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().doesNotExist("X-Custom-Header");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotExistFail() {
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
|
||||
testClient.get().uri("/persons/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().doesNotExist(LAST_MODIFIED));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longValueWithIncorrectResponseHeaderValue() {
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
|
||||
testClient.get().uri("/persons/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEquals("X-Rate-Limiting", 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringWithMatcherAndIncorrectResponseHeaderValue() {
|
||||
long secondLater = this.currentTime + 1000;
|
||||
String expected = this.dateFormat.format(new Date(secondLater));
|
||||
assertIncorrectResponseHeader(spec -> spec.expectHeader().valueEquals(LAST_MODIFIED, expected), expected);
|
||||
assertIncorrectResponseHeader(spec -> spec.expectHeader().value(LAST_MODIFIED, equalTo(expected)), expected);
|
||||
// Comparison by date uses HttpHeaders to format the date in the error message.
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setDate("expected", secondLater);
|
||||
assertIncorrectResponseHeader(spec -> spec.expectHeader().valueEqualsDate(LAST_MODIFIED, secondLater), expected);
|
||||
}
|
||||
|
||||
private void assertIncorrectResponseHeader(Consumer<WebTestClient.ResponseSpec> assertions, String expected) {
|
||||
try {
|
||||
WebTestClient.ResponseSpec spec = testClient.get().uri("/persons/1")
|
||||
.header(IF_MODIFIED_SINCE, minuteAgo)
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
assertions.accept(spec);
|
||||
|
||||
fail(ERROR_MESSAGE);
|
||||
}
|
||||
catch (AssertionError err) {
|
||||
if (ERROR_MESSAGE.equals(err.getMessage())) {
|
||||
throw err;
|
||||
}
|
||||
assertMessageContains(err, "Response header '" + LAST_MODIFIED + "'");
|
||||
assertMessageContains(err, expected);
|
||||
assertMessageContains(err, this.now);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertMessageContains(AssertionError error, String expected) {
|
||||
assertThat(error.getMessage().contains(expected))
|
||||
.as("Failure message should contain [" + expected + "], actual is [" + error.getMessage() + "]")
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class PersonController {
|
||||
|
||||
private long timestamp;
|
||||
|
||||
public void setStubTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@RequestMapping("/persons/{id}")
|
||||
public ResponseEntity<Person> showEntity(@PathVariable long id, WebRequest request) {
|
||||
return ResponseEntity
|
||||
.ok()
|
||||
.lastModified(this.timestamp)
|
||||
.header("X-Rate-Limiting", "42")
|
||||
.header("Vary", "foo", "bar")
|
||||
.body(new Person("Jason"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.in;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.JsonPathAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class JsonPathAssertionTests {
|
||||
|
||||
private final WebTestClient client =
|
||||
MockMvcTestClient.bindToController(new MusicController())
|
||||
.alwaysExpect(status().isOk())
|
||||
.alwaysExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.configureClient()
|
||||
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.build();
|
||||
|
||||
|
||||
@Test
|
||||
public void exists() {
|
||||
String composerByName = "$.composers[?(@.name == '%s')]";
|
||||
String performerByName = "$.performers[?(@.name == '%s')]";
|
||||
|
||||
client.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.jsonPath(composerByName, "Johann Sebastian Bach").exists()
|
||||
.jsonPath(composerByName, "Johannes Brahms").exists()
|
||||
.jsonPath(composerByName, "Edvard Grieg").exists()
|
||||
.jsonPath(composerByName, "Robert Schumann").exists()
|
||||
.jsonPath(performerByName, "Vladimir Ashkenazy").exists()
|
||||
.jsonPath(performerByName, "Yehudi Menuhin").exists()
|
||||
.jsonPath("$.composers[0]").exists()
|
||||
.jsonPath("$.composers[1]").exists()
|
||||
.jsonPath("$.composers[2]").exists()
|
||||
.jsonPath("$.composers[3]").exists();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotExist() {
|
||||
client.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.jsonPath("$.composers[?(@.name == 'Edvard Grieeeeeeg')]").doesNotExist()
|
||||
.jsonPath("$.composers[?(@.name == 'Robert Schuuuuuuman')]").doesNotExist()
|
||||
.jsonPath("$.composers[4]").doesNotExist();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equality() {
|
||||
client.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.jsonPath("$.composers[0].name").isEqualTo("Johann Sebastian Bach")
|
||||
.jsonPath("$.performers[1].name").isEqualTo("Yehudi Menuhin");
|
||||
|
||||
// Hamcrest matchers...
|
||||
client.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody()
|
||||
.jsonPath("$.composers[0].name").value(equalTo("Johann Sebastian Bach"))
|
||||
.jsonPath("$.performers[1].name").value(equalTo("Yehudi Menuhin"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hamcrestMatcher() {
|
||||
client.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.jsonPath("$.composers[0].name").value(startsWith("Johann"))
|
||||
.jsonPath("$.performers[0].name").value(endsWith("Ashkenazy"))
|
||||
.jsonPath("$.performers[1].name").value(containsString("di Me"))
|
||||
.jsonPath("$.composers[1].name").value(is(in(Arrays.asList("Johann Sebastian Bach", "Johannes Brahms"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hamcrestMatcherWithParameterizedJsonPath() {
|
||||
String composerName = "$.composers[%s].name";
|
||||
String performerName = "$.performers[%s].name";
|
||||
|
||||
client.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.jsonPath(composerName, 0).value(startsWith("Johann"))
|
||||
.jsonPath(performerName, 0).value(endsWith("Ashkenazy"))
|
||||
.jsonPath(performerName, 1).value(containsString("di Me"))
|
||||
.jsonPath(composerName, 1).value(is(in(Arrays.asList("Johann Sebastian Bach", "Johannes Brahms"))));
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
private class MusicController {
|
||||
|
||||
@RequestMapping("/music/people")
|
||||
public MultiValueMap<String, Person> get() {
|
||||
MultiValueMap<String, Person> map = new LinkedMultiValueMap<>();
|
||||
|
||||
map.add("composers", new Person("Johann Sebastian Bach"));
|
||||
map.add("composers", new Person("Johannes Brahms"));
|
||||
map.add("composers", new Person("Edvard Grieg"));
|
||||
map.add("composers", new Person("Robert Schumann"));
|
||||
|
||||
map.add("performers", new Person("Vladimir Ashkenazy"));
|
||||
map.add("performers", new Person("Yehudi Menuhin"));
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasProperty;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.ModelAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ModelAssertionTests {
|
||||
|
||||
private final WebTestClient client =
|
||||
MockMvcTestClient.bindToController(new SampleController("a string value", 3, new Person("a name")))
|
||||
.controllerAdvice(new ModelAttributeAdvice())
|
||||
.alwaysExpect(status().isOk())
|
||||
.build();
|
||||
|
||||
@Test
|
||||
void attributeEqualTo() throws Exception {
|
||||
performRequest(HttpMethod.GET, "/")
|
||||
.andExpect(model().attribute("integer", 3))
|
||||
.andExpect(model().attribute("string", "a string value"))
|
||||
.andExpect(model().attribute("integer", equalTo(3))) // Hamcrest...
|
||||
.andExpect(model().attribute("string", equalTo("a string value")))
|
||||
.andExpect(model().attribute("globalAttrName", equalTo("Global Attribute Value")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void attributeExists() throws Exception {
|
||||
performRequest(HttpMethod.GET, "/")
|
||||
.andExpect(model().attributeExists("integer", "string", "person"))
|
||||
.andExpect(model().attribute("integer", notNullValue())) // Hamcrest...
|
||||
.andExpect(model().attribute("INTEGER", nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void attributeHamcrestMatchers() throws Exception {
|
||||
performRequest(HttpMethod.GET, "/")
|
||||
.andExpect(model().attribute("integer", equalTo(3)))
|
||||
.andExpect(model().attribute("string", allOf(startsWith("a string"), endsWith("value"))))
|
||||
.andExpect(model().attribute("person", hasProperty("name", equalTo("a name"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasErrors() throws Exception {
|
||||
performRequest(HttpMethod.POST, "/persons").andExpect(model().attributeHasErrors("person"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasNoErrors() throws Exception {
|
||||
performRequest(HttpMethod.GET, "/").andExpect(model().hasNoErrors());
|
||||
}
|
||||
|
||||
private ResultActions performRequest(HttpMethod method, String uri) {
|
||||
EntityExchangeResult<Void> result = client.method(method).uri(uri).exchange().expectBody().isEmpty();
|
||||
return MockMvcTestClient.resultActionsFor(result);
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class SampleController {
|
||||
|
||||
private final Object[] values;
|
||||
|
||||
SampleController(Object... values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@RequestMapping("/")
|
||||
String handle(Model model) {
|
||||
for (Object value : this.values) {
|
||||
model.addAttribute(value);
|
||||
}
|
||||
return "view";
|
||||
}
|
||||
|
||||
@PostMapping("/persons")
|
||||
String create(@Valid Person person, BindingResult result, Model model) {
|
||||
return "view";
|
||||
}
|
||||
}
|
||||
|
||||
@ControllerAdvice
|
||||
private static class ModelAttributeAdvice {
|
||||
|
||||
@ModelAttribute("globalAttrName")
|
||||
String getAttribute() {
|
||||
return "Global Attribute Value";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.RequestAttributeAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class RequestAttributeAssertionTests {
|
||||
|
||||
private final WebTestClient mainServletClient =
|
||||
MockMvcTestClient.bindToController(new SimpleController())
|
||||
.defaultRequest(get("/").servletPath("/main"))
|
||||
.build();
|
||||
|
||||
private final WebTestClient client =
|
||||
MockMvcTestClient.bindToController(new SimpleController()).build();
|
||||
|
||||
|
||||
@Test
|
||||
void requestAttributeEqualTo() throws Exception {
|
||||
performRequest(mainServletClient, "/main/1")
|
||||
.andExpect(request().attribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/{id}"))
|
||||
.andExpect(request().attribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void requestAttributeMatcher() throws Exception {
|
||||
String producibleMediaTypes = HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE;
|
||||
|
||||
performRequest(client, "/1")
|
||||
.andExpect(request().attribute(producibleMediaTypes, hasItem(MediaType.APPLICATION_JSON)))
|
||||
.andExpect(request().attribute(producibleMediaTypes, not(hasItem(MediaType.APPLICATION_XML))));
|
||||
|
||||
performRequest(mainServletClient, "/main/1")
|
||||
.andExpect(request().attribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, equalTo("/{id}")))
|
||||
.andExpect(request().attribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, equalTo("/1")));
|
||||
}
|
||||
|
||||
private ResultActions performRequest(WebTestClient client, String uri) {
|
||||
EntityExchangeResult<Void> result = client.get().uri(uri)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
return MockMvcTestClient.resultActionsFor(result);
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class SimpleController {
|
||||
|
||||
@GetMapping(path="/{id}", produces="application/json")
|
||||
String show() {
|
||||
return "view";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.SessionAttributeAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class SessionAttributeAssertionTests {
|
||||
|
||||
private final WebTestClient client =
|
||||
MockMvcTestClient.bindToController(new SimpleController())
|
||||
.alwaysExpect(status().isOk())
|
||||
.build();
|
||||
|
||||
|
||||
@Test
|
||||
void sessionAttributeEqualTo() throws Exception {
|
||||
performRequest().andExpect(request().sessionAttribute("locale", Locale.UK));
|
||||
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> performRequest().andExpect(request().sessionAttribute("locale", Locale.US)))
|
||||
.withMessage("Session attribute 'locale' expected:<en_US> but was:<en_GB>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionAttributeMatcher() throws Exception {
|
||||
performRequest()
|
||||
.andExpect(request().sessionAttribute("bogus", is(nullValue())))
|
||||
.andExpect(request().sessionAttribute("locale", is(notNullValue())))
|
||||
.andExpect(request().sessionAttribute("locale", equalTo(Locale.UK)));
|
||||
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> performRequest().andExpect(request().sessionAttribute("bogus", is(notNullValue()))))
|
||||
.withMessageContaining("null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionAttributeDoesNotExist() throws Exception {
|
||||
performRequest().andExpect(request().sessionAttributeDoesNotExist("bogus", "enigma"));
|
||||
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> performRequest().andExpect(request().sessionAttributeDoesNotExist("locale")))
|
||||
.withMessage("Session attribute 'locale' exists");
|
||||
}
|
||||
|
||||
private ResultActions performRequest() {
|
||||
EntityExchangeResult<Void> result = client.post().uri("/").exchange().expectBody().isEmpty();
|
||||
return MockMvcTestClient.resultActionsFor(result);
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
@SessionAttributes("locale")
|
||||
private static class SimpleController {
|
||||
|
||||
@ModelAttribute
|
||||
void populate(Model model) {
|
||||
model.addAttribute("locale", Locale.UK);
|
||||
}
|
||||
|
||||
@RequestMapping("/")
|
||||
String handle() {
|
||||
return "view";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
import static org.springframework.http.HttpStatus.NOT_IMPLEMENTED;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.StatusAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class StatusAssertionTests {
|
||||
|
||||
private final WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new StatusController()).build();
|
||||
|
||||
|
||||
@Test
|
||||
public void testStatusInt() {
|
||||
testClient.get().uri("/created").exchange().expectStatus().isEqualTo(201);
|
||||
testClient.get().uri("/createdWithComposedAnnotation").exchange().expectStatus().isEqualTo(201);
|
||||
testClient.get().uri("/badRequest").exchange().expectStatus().isEqualTo(400);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpStatus() {
|
||||
testClient.get().uri("/created").exchange().expectStatus().isCreated();
|
||||
testClient.get().uri("/createdWithComposedAnnotation").exchange().expectStatus().isCreated();
|
||||
testClient.get().uri("/badRequest").exchange().expectStatus().isBadRequest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatcher() {
|
||||
testClient.get().uri("/badRequest").exchange().expectStatus().value(equalTo(400));
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping
|
||||
@ResponseStatus
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Get {
|
||||
|
||||
@AliasFor(annotation = RequestMapping.class, attribute = "path")
|
||||
String[] path() default {};
|
||||
|
||||
@AliasFor(annotation = ResponseStatus.class, attribute = "code")
|
||||
HttpStatus status() default INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
@Controller
|
||||
private static class StatusController {
|
||||
|
||||
@RequestMapping("/created")
|
||||
@ResponseStatus(CREATED)
|
||||
public @ResponseBody void created(){
|
||||
}
|
||||
|
||||
@Get(path = "/createdWithComposedAnnotation", status = CREATED)
|
||||
public @ResponseBody void createdWithComposedAnnotation() {
|
||||
}
|
||||
|
||||
@RequestMapping("/badRequest")
|
||||
@ResponseStatus(code = BAD_REQUEST, reason = "Expired token")
|
||||
public @ResponseBody void badRequest(){
|
||||
}
|
||||
|
||||
@RequestMapping("/notImplemented")
|
||||
@ResponseStatus(NOT_IMPLEMENTED)
|
||||
public @ResponseBody void notImplemented(){
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrlPattern;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.UrlAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class UrlAssertionTests {
|
||||
|
||||
private final WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new SimpleController()).build();
|
||||
|
||||
|
||||
@Test
|
||||
public void testRedirect() {
|
||||
testClient.get().uri("/persons")
|
||||
.exchange()
|
||||
.expectStatus().isFound()
|
||||
.expectHeader().location("/persons/1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectPattern() throws Exception {
|
||||
EntityExchangeResult<Void> result =
|
||||
testClient.get().uri("/persons").exchange().expectBody().isEmpty();
|
||||
|
||||
MockMvcTestClient.resultActionsFor(result)
|
||||
.andExpect(redirectedUrlPattern("/persons/*"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForward() {
|
||||
testClient.get().uri("/")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueEquals("Forwarded-Url", "/home");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForwardPattern() throws Exception {
|
||||
EntityExchangeResult<Void> result =
|
||||
testClient.get().uri("/").exchange().expectBody().isEmpty();
|
||||
|
||||
MockMvcTestClient.resultActionsFor(result)
|
||||
.andExpect(forwardedUrlPattern("/ho?e"));
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class SimpleController {
|
||||
|
||||
@RequestMapping("/persons")
|
||||
public String save() {
|
||||
return "redirect:/persons/1";
|
||||
}
|
||||
|
||||
@RequestMapping("/")
|
||||
public String forward() {
|
||||
return "forward:/home";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.UrlAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ViewNameAssertionTests {
|
||||
|
||||
private final WebTestClient client =
|
||||
MockMvcTestClient.bindToController(new SimpleController())
|
||||
.alwaysExpect(status().isOk())
|
||||
.build();
|
||||
|
||||
|
||||
@Test
|
||||
public void testEqualTo() throws Exception {
|
||||
MockMvcTestClient.resultActionsFor(performRequest())
|
||||
.andExpect(view().name("mySpecialView"))
|
||||
.andExpect(view().name(equalTo("mySpecialView")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHamcrestMatcher() throws Exception {
|
||||
MockMvcTestClient.resultActionsFor(performRequest())
|
||||
.andExpect(view().name(containsString("Special")));
|
||||
}
|
||||
|
||||
private EntityExchangeResult<Void> performRequest() {
|
||||
return client.get().uri("/").exchange().expectBody().isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class SimpleController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public String handle() {
|
||||
return "mySpecialView";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.XmlContentAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class XmlContentAssertionTests {
|
||||
|
||||
private static final String PEOPLE_XML =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
|
||||
"<people><composers>" +
|
||||
"<composer><name>Johann Sebastian Bach</name><someBoolean>false</someBoolean><someDouble>21.0</someDouble></composer>" +
|
||||
"<composer><name>Johannes Brahms</name><someBoolean>false</someBoolean><someDouble>0.0025</someDouble></composer>" +
|
||||
"<composer><name>Edvard Grieg</name><someBoolean>false</someBoolean><someDouble>1.6035</someDouble></composer>" +
|
||||
"<composer><name>Robert Schumann</name><someBoolean>false</someBoolean><someDouble>NaN</someDouble></composer>" +
|
||||
"</composers></people>";
|
||||
|
||||
|
||||
private final WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new MusicController())
|
||||
.alwaysExpect(status().isOk())
|
||||
.alwaysExpect(content().contentType(MediaType.parseMediaType("application/xml;charset=UTF-8")))
|
||||
.configureClient()
|
||||
.defaultHeader(HttpHeaders.ACCEPT, "application/xml;charset=UTF-8")
|
||||
.build();
|
||||
|
||||
|
||||
@Test
|
||||
public void testXmlEqualTo() {
|
||||
testClient.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody().xml(PEOPLE_XML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNodeHamcrestMatcher() {
|
||||
testClient.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody().xpath("/people/composers/composer[1]").exists();
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class MusicController {
|
||||
|
||||
@RequestMapping(value="/music/people")
|
||||
public @ResponseBody PeopleWrapper getPeople() {
|
||||
|
||||
List<Person> composers = Arrays.asList(
|
||||
new Person("Johann Sebastian Bach").setSomeDouble(21),
|
||||
new Person("Johannes Brahms").setSomeDouble(.0025),
|
||||
new Person("Edvard Grieg").setSomeDouble(1.6035),
|
||||
new Person("Robert Schumann").setSomeDouble(Double.NaN));
|
||||
|
||||
return new PeopleWrapper(composers);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@XmlRootElement(name="people")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
private static class PeopleWrapper {
|
||||
|
||||
@XmlElementWrapper(name="composers")
|
||||
@XmlElement(name="composer")
|
||||
private List<Person> composers;
|
||||
|
||||
public PeopleWrapper() {
|
||||
}
|
||||
|
||||
public PeopleWrapper(List<Person> composers) {
|
||||
this.composers = composers;
|
||||
}
|
||||
|
||||
public List<Person> getComposers() {
|
||||
return this.composers;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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.servlet.samples.client.standalone.resultmatches;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcTestClient;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import static org.hamcrest.Matchers.closeTo;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.HEAD;
|
||||
|
||||
/**
|
||||
* MockMvcTestClient equivalent of the MockMvc
|
||||
* {@link org.springframework.test.web.servlet.samples.standalone.resultmatchers.XpathAssertionTests}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class XpathAssertionTests {
|
||||
|
||||
private static final Map<String, String> musicNamespace =
|
||||
Collections.singletonMap("ns", "https://example.org/music/people");
|
||||
|
||||
private final WebTestClient testClient =
|
||||
MockMvcTestClient.bindToController(new MusicController())
|
||||
.alwaysExpect(status().isOk())
|
||||
.alwaysExpect(content().contentType(MediaType.parseMediaType("application/xml;charset=UTF-8")))
|
||||
.configureClient()
|
||||
.defaultHeader(HttpHeaders.ACCEPT, "application/xml;charset=UTF-8")
|
||||
.build();
|
||||
|
||||
|
||||
@Test
|
||||
public void testExists() {
|
||||
String composer = "/ns:people/composers/composer[%s]";
|
||||
String performer = "/ns:people/performers/performer[%s]";
|
||||
|
||||
testClient.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.xpath(composer, musicNamespace, 1).exists()
|
||||
.xpath(composer, musicNamespace, 2).exists()
|
||||
.xpath(composer, musicNamespace, 3).exists()
|
||||
.xpath(composer, musicNamespace, 4).exists()
|
||||
.xpath(performer, musicNamespace, 1).exists()
|
||||
.xpath(performer, musicNamespace, 2).exists()
|
||||
.xpath(composer, musicNamespace, 1).string(notNullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoesNotExist() {
|
||||
String composer = "/ns:people/composers/composer[%s]";
|
||||
String performer = "/ns:people/performers/performer[%s]";
|
||||
|
||||
testClient.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.xpath(composer, musicNamespace, 0).doesNotExist()
|
||||
.xpath(composer, musicNamespace, 5).doesNotExist()
|
||||
.xpath(performer, musicNamespace, 0).doesNotExist()
|
||||
.xpath(performer, musicNamespace, 3).doesNotExist();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testString() {
|
||||
|
||||
String composerName = "/ns:people/composers/composer[%s]/name";
|
||||
String performerName = "/ns:people/performers/performer[%s]/name";
|
||||
|
||||
testClient.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.xpath(composerName, musicNamespace, 1).isEqualTo("Johann Sebastian Bach")
|
||||
.xpath(composerName, musicNamespace, 2).isEqualTo("Johannes Brahms")
|
||||
.xpath(composerName, musicNamespace, 3).isEqualTo("Edvard Grieg")
|
||||
.xpath(composerName, musicNamespace, 4).isEqualTo("Robert Schumann")
|
||||
.xpath(performerName, musicNamespace, 1).isEqualTo("Vladimir Ashkenazy")
|
||||
.xpath(performerName, musicNamespace, 2).isEqualTo("Yehudi Menuhin")
|
||||
.xpath(composerName, musicNamespace, 1).string(equalTo("Johann Sebastian Bach")) // Hamcrest..
|
||||
.xpath(composerName, musicNamespace, 1).string(startsWith("Johann"))
|
||||
.xpath(composerName, musicNamespace, 1).string(notNullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumber() {
|
||||
String expression = "/ns:people/composers/composer[%s]/someDouble";
|
||||
|
||||
testClient.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.xpath(expression, musicNamespace, 1).isEqualTo(21d)
|
||||
.xpath(expression, musicNamespace, 2).isEqualTo(.0025)
|
||||
.xpath(expression, musicNamespace, 3).isEqualTo(1.6035)
|
||||
.xpath(expression, musicNamespace, 4).isEqualTo(Double.NaN)
|
||||
.xpath(expression, musicNamespace, 1).number(equalTo(21d)) // Hamcrest..
|
||||
.xpath(expression, musicNamespace, 3).number(closeTo(1.6, .01));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoolean() {
|
||||
String expression = "/ns:people/performers/performer[%s]/someBoolean";
|
||||
|
||||
testClient.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.xpath(expression, musicNamespace, 1).isEqualTo(false)
|
||||
.xpath(expression, musicNamespace, 2).isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNodeCount() {
|
||||
testClient.get().uri("/music/people")
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.xpath("/ns:people/composers/composer", musicNamespace).nodeCount(4)
|
||||
.xpath("/ns:people/performers/performer", musicNamespace).nodeCount(2)
|
||||
.xpath("/ns:people/composers/composer", musicNamespace).nodeCount(equalTo(4)) // Hamcrest..
|
||||
.xpath("/ns:people/performers/performer", musicNamespace).nodeCount(equalTo(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeedWithLinefeedChars() {
|
||||
MockMvcTestClient.bindToController(new BlogFeedController()).build()
|
||||
.get().uri("/blog.atom")
|
||||
.accept(MediaType.APPLICATION_ATOM_XML)
|
||||
.exchange()
|
||||
.expectBody()
|
||||
.xpath("//feed/title").isEqualTo("Test Feed")
|
||||
.xpath("//feed/icon").isEqualTo("https://www.example.com/favicon.ico");
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class MusicController {
|
||||
|
||||
@RequestMapping(value = "/music/people")
|
||||
public @ResponseBody
|
||||
PeopleWrapper getPeople() {
|
||||
|
||||
List<Person> composers = Arrays.asList(
|
||||
new Person("Johann Sebastian Bach").setSomeDouble(21),
|
||||
new Person("Johannes Brahms").setSomeDouble(.0025),
|
||||
new Person("Edvard Grieg").setSomeDouble(1.6035),
|
||||
new Person("Robert Schumann").setSomeDouble(Double.NaN));
|
||||
|
||||
List<Person> performers = Arrays.asList(
|
||||
new Person("Vladimir Ashkenazy").setSomeBoolean(false),
|
||||
new Person("Yehudi Menuhin").setSomeBoolean(true));
|
||||
|
||||
return new PeopleWrapper(composers, performers);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@XmlRootElement(name = "people", namespace = "https://example.org/music/people")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
private static class PeopleWrapper {
|
||||
|
||||
@XmlElementWrapper(name = "composers")
|
||||
@XmlElement(name = "composer")
|
||||
private List<Person> composers;
|
||||
|
||||
@XmlElementWrapper(name = "performers")
|
||||
@XmlElement(name = "performer")
|
||||
private List<Person> performers;
|
||||
|
||||
public PeopleWrapper() {
|
||||
}
|
||||
|
||||
public PeopleWrapper(List<Person> composers, List<Person> performers) {
|
||||
this.composers = composers;
|
||||
this.performers = performers;
|
||||
}
|
||||
|
||||
public List<Person> getComposers() {
|
||||
return this.composers;
|
||||
}
|
||||
|
||||
public List<Person> getPerformers() {
|
||||
return this.performers;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
public class BlogFeedController {
|
||||
|
||||
@RequestMapping(value = "/blog.atom", method = {GET, HEAD})
|
||||
@ResponseBody
|
||||
public String listPublishedPosts() {
|
||||
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
|
||||
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">\r\n"
|
||||
+ " <title>Test Feed</title>\r\n"
|
||||
+ " <icon>https://www.example.com/favicon.ico</icon>\r\n"
|
||||
+ "</feed>\r\n\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public class PersonController {
|
||||
private final PersonDao personDao;
|
||||
|
||||
|
||||
PersonController(PersonDao personDao) {
|
||||
public PersonController(PersonDao personDao) {
|
||||
this.personDao = personDao;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 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.
|
||||
@@ -18,12 +18,12 @@ package org.springframework.test.web.servlet.samples.standalone;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -113,8 +113,6 @@ public class AsyncTests {
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
|
||||
this.asyncController.onMessage("Joe");
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
@@ -151,8 +149,6 @@ public class AsyncTests {
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
|
||||
this.asyncController.onMessage("Joe");
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
@@ -183,8 +179,6 @@ public class AsyncTests {
|
||||
assertThat(writer.toString().contains("Async started = true")).isTrue();
|
||||
writer = new StringWriter();
|
||||
|
||||
this.asyncController.onMessage("Joe");
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andDo(print(writer))
|
||||
.andExpect(status().isOk())
|
||||
@@ -199,10 +193,6 @@ public class AsyncTests {
|
||||
@RequestMapping(path = "/{id}", produces = "application/json")
|
||||
private static class AsyncController {
|
||||
|
||||
private final Collection<DeferredResult<Person>> deferredResults = new CopyOnWriteArrayList<>();
|
||||
|
||||
private final Collection<ListenableFutureTask<Person>> futureTasks = new CopyOnWriteArrayList<>();
|
||||
|
||||
@RequestMapping(params = "callable")
|
||||
public Callable<Person> getCallable() {
|
||||
return () -> new Person("Joe");
|
||||
@@ -235,9 +225,9 @@ public class AsyncTests {
|
||||
|
||||
@RequestMapping(params = "deferredResult")
|
||||
public DeferredResult<Person> getDeferredResult() {
|
||||
DeferredResult<Person> deferredResult = new DeferredResult<>();
|
||||
this.deferredResults.add(deferredResult);
|
||||
return deferredResult;
|
||||
DeferredResult<Person> result = new DeferredResult<>();
|
||||
delay(100, () -> result.setResult(new Person("Joe")));
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(params = "deferredResultWithImmediateValue")
|
||||
@@ -249,26 +239,15 @@ public class AsyncTests {
|
||||
|
||||
@RequestMapping(params = "deferredResultWithDelayedError")
|
||||
public DeferredResult<Person> getDeferredResultWithDelayedError() {
|
||||
final DeferredResult<Person> deferredResult = new DeferredResult<>();
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
deferredResult.setErrorResult(new RuntimeException("Delayed Error"));
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
return deferredResult;
|
||||
DeferredResult<Person> result = new DeferredResult<>();
|
||||
delay(100, () -> result.setErrorResult(new RuntimeException("Delayed Error")));
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(params = "listenableFuture")
|
||||
public ListenableFuture<Person> getListenableFuture() {
|
||||
ListenableFutureTask<Person> futureTask = new ListenableFutureTask<>(() -> new Person("Joe"));
|
||||
this.futureTasks.add(futureTask);
|
||||
delay(100, futureTask);
|
||||
return futureTask;
|
||||
}
|
||||
|
||||
@@ -281,19 +260,12 @@ public class AsyncTests {
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public String errorHandler(Exception e) {
|
||||
return e.getMessage();
|
||||
public String errorHandler(Exception ex) {
|
||||
return ex.getMessage();
|
||||
}
|
||||
|
||||
void onMessage(String name) {
|
||||
for (DeferredResult<Person> deferredResult : this.deferredResults) {
|
||||
deferredResult.setResult(new Person(name));
|
||||
this.deferredResults.remove(deferredResult);
|
||||
}
|
||||
for (ListenableFutureTask<Person> futureTask : this.futureTasks) {
|
||||
futureTask.run();
|
||||
this.futureTasks.remove(futureTask);
|
||||
}
|
||||
private void delay(long millis, Runnable task) {
|
||||
Mono.delay(Duration.ofMillis(millis)).doOnTerminate(task).subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class ExceptionHandlerTests {
|
||||
public class ExceptionHandlerTests {
|
||||
|
||||
@Nested
|
||||
class MvcTests {
|
||||
@@ -62,14 +62,6 @@ class ExceptionHandlerTests {
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(forwardedUrl("globalErrorView"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalExceptionHandlerMethodUsingClassArgument() throws Exception {
|
||||
standaloneSetup(PersonController.class).setControllerAdvice(GlobalExceptionHandler.class).build()
|
||||
.perform(get("/person/Bonnie"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(forwardedUrl("globalErrorView"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +138,7 @@ class ExceptionHandlerTests {
|
||||
void noHandlerFound() throws Exception {
|
||||
standaloneSetup(RestPersonController.class)
|
||||
.setControllerAdvice(RestGlobalExceptionHandler.class, RestPersonControllerExceptionHandler.class)
|
||||
.addDispatcherServletCustomizer(dispatcherServlet -> dispatcherServlet.setThrowExceptionIfNoHandlerFound(true))
|
||||
.addDispatcherServletCustomizer(servlet -> servlet.setThrowExceptionIfNoHandlerFound(true))
|
||||
.build()
|
||||
.perform(get("/bogus").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
|
||||
@@ -48,9 +48,12 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal
|
||||
* @author Sam Brannen
|
||||
* @see org.springframework.test.web.servlet.result.PrintingResultHandlerTests
|
||||
*/
|
||||
@Disabled("Not intended to be executed with the build. Comment out this line to inspect the output manually.")
|
||||
@Disabled
|
||||
public class PrintingResultHandlerSmokeTests {
|
||||
|
||||
// Not intended to be executed with the build.
|
||||
// Comment out class-level @Disabled to see the output.
|
||||
|
||||
@Test
|
||||
public void testPrint() throws Exception {
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
@@ -41,7 +41,7 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class FlashAttributeAssertionTests {
|
||||
public class FlashAttributeAssertionTests {
|
||||
|
||||
private final MockMvc mockMvc = standaloneSetup(new PersonController())
|
||||
.alwaysExpect(status().isFound())
|
||||
|
||||
@@ -49,7 +49,7 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
class ModelAssertionTests {
|
||||
public class ModelAssertionTests {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
class RequestAttributeAssertionTests {
|
||||
public class RequestAttributeAssertionTests {
|
||||
|
||||
private final MockMvc mockMvc = standaloneSetup(new SimpleController()).build();
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class SessionAttributeAssertionTests {
|
||||
public class SessionAttributeAssertionTests {
|
||||
|
||||
private final MockMvc mockMvc = standaloneSetup(new SimpleController())
|
||||
.defaultRequest(get("/"))
|
||||
|
||||
Reference in New Issue
Block a user