Browse Source

Refactor view resolution tests

pull/1111/head
Rossen Stoyanchev 10 years ago
parent
commit
49bb83c0ec
  1. 375
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandlerTests.java

375
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandlerTests.java

@ -16,8 +16,8 @@
package org.springframework.web.reactive.result.view; package org.springframework.web.reactive.result.view;
import java.lang.reflect.Method;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.time.Duration; import java.time.Duration;
@ -37,7 +37,6 @@ import rx.Single;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.convert.support.ReactiveStreamsToRxJava1Converter; import org.springframework.core.convert.support.ReactiveStreamsToRxJava1Converter;
@ -49,6 +48,7 @@ import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.MockServerHttpRequest; import org.springframework.http.server.reactive.MockServerHttpRequest;
import org.springframework.http.server.reactive.MockServerHttpResponse; import org.springframework.http.server.reactive.MockServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
@ -62,10 +62,9 @@ import org.springframework.web.server.session.DefaultWebSessionManager;
import org.springframework.web.server.session.WebSessionManager; import org.springframework.web.server.session.WebSessionManager;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.springframework.http.MediaType.APPLICATION_JSON;
/** /**
* Unit tests for {@link ViewResolutionResultHandler}. * Unit tests for {@link ViewResolutionResultHandler}.
@ -75,247 +74,209 @@ public class ViewResolutionResultHandlerTests {
private MockServerHttpRequest request; private MockServerHttpRequest request;
private MockServerHttpResponse response; private MockServerHttpResponse response = new MockServerHttpResponse();
private ModelMap model; private ServerWebExchange exchange;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
this.model = new ExtendedModelMap().addAttribute("id", "123");
this.request = new MockServerHttpRequest(HttpMethod.GET, new URI("/path")); this.request = new MockServerHttpRequest(HttpMethod.GET, new URI("/path"));
this.response = new MockServerHttpResponse(); WebSessionManager manager = new DefaultWebSessionManager();
this.exchange = new DefaultServerWebExchange(this.request, this.response, manager);
} }
@Test @Test
public void supports() throws Exception { public void supports() throws Exception {
testSupports("handleString", true); Object handler = new Object();
testSupports("handleView", true); HandlerMethod hm = handlerMethod(new TestController(), "modelAttributeMethod");
testSupports("handleMonoString", true);
testSupports("handleMonoView", true); testSupports(handler, ResolvableType.forClass(String.class), true);
testSupports("handleSingleString", true); testSupports(handler, ResolvableType.forClass(View.class), true);
testSupports("handleSingleView", true); testSupports(handler, ResolvableType.forClassWithGenerics(Mono.class, String.class), true);
testSupports("handleModel", true); testSupports(handler, ResolvableType.forClassWithGenerics(Mono.class, View.class), true);
testSupports("handleMap", true); testSupports(handler, ResolvableType.forClassWithGenerics(Single.class, String.class), true);
testSupports("handleModelAttributeAnnotation", true); testSupports(handler, ResolvableType.forClassWithGenerics(Single.class, View.class), true);
testSupports("handleTestBean", true); testSupports(handler, ResolvableType.forClass(Model.class), true);
testSupports("handleInteger", false); testSupports(handler, ResolvableType.forClass(Map.class), true);
testSupports(handler, ResolvableType.forClass(TestBean.class), true);
testSupports(handler, ResolvableType.forClass(Integer.class), false);
testSupports(hm, ResolvableType.forMethodParameter(hm.getReturnType()), true);
}
private void testSupports(Object handler, ResolvableType returnType, boolean result) {
ViewResolutionResultHandler resultHandler = createResultHandler(mock(ViewResolver.class));
HandlerResult handlerResult = new HandlerResult(handler, null, returnType, new ExtendedModelMap());
assertEquals(result, resultHandler.supports(handlerResult));
} }
@Test @Test
public void order() throws Exception { public void viewResolverOrder() throws Exception {
TestViewResolver resolver1 = new TestViewResolver(new String[] {}); TestViewResolver resolver1 = new TestViewResolver("account");
TestViewResolver resolver2 = new TestViewResolver(new String[] {}); TestViewResolver resolver2 = new TestViewResolver("profile");
resolver1.setOrder(2); resolver1.setOrder(2);
resolver2.setOrder(1); resolver2.setOrder(1);
List<ViewResolver> resolvers = createResultHandler(resolver1, resolver2).getViewResolvers();
assertEquals(Arrays.asList(resolver2, resolver1), new ViewResolutionResultHandler( assertEquals(Arrays.asList(resolver2, resolver1), resolvers);
Arrays.asList(resolver1, resolver2), new DefaultConversionService())
.getViewResolvers());
} }
@Test @Test
public void viewReference() throws Exception { public void handleReturnValueTypes() throws Exception {
Object value = new TestView("account"); Object handler = new Object();
handle("/path", value, "handleView"); Object returnValue;
ResolvableType returnType;
TestSubscriber.subscribe(this.response.getBody()) ViewResolver resolver = new TestViewResolver("account");
.assertValuesWith(buf -> assertEquals("account: {id=123}",
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8"))));
}
@Test
public void viewReferenceInMono() throws Exception {
Object value = Mono.just(new TestView("account"));
handle("/path", value, "handleMonoView");
TestSubscriber.subscribe(this.response.getBody()) returnValue = new TestView("account");
.assertValuesWith(buf -> assertEquals("account: {id=123}", returnType = ResolvableType.forClass(View.class);
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8")))); testHandle("/path", handler, returnValue, returnType, "account: {id=123}");
}
@Test returnValue = Mono.just(new TestView("account"));
public void viewName() throws Exception { returnType = ResolvableType.forClassWithGenerics(Mono.class, View.class);
Object value = "account"; testHandle("/path", handler, returnValue, returnType, "account: {id=123}");
handle("/path", value, "handleString", new TestViewResolver("account"));
TestSubscriber returnValue = "account";
.subscribe(this.response.getBody()) returnType = ResolvableType.forClass(String.class);
.assertValuesWith(buf -> assertEquals("account: {id=123}", testHandle("/path", handler, returnValue, returnType, "account: {id=123}", resolver);
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8"))));
}
@Test returnValue = Mono.just("account");
public void viewNameMono() throws Exception { returnType = ResolvableType.forClassWithGenerics(Mono.class, String.class);
Object value = Mono.just("account"); testHandle("/path", handler, returnValue, returnType, "account: {id=123}", resolver);
handle("/path", value, "handleMonoString", new TestViewResolver("account"));
TestSubscriber.subscribe(this.response.getBody()) returnValue = new ExtendedModelMap().addAttribute("name", "Joe");
.assertValuesWith(buf -> assertEquals("account: {id=123}", returnType = ResolvableType.forClass(Model.class);
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8")))); testHandle("/account", handler, returnValue, returnType, "account: {id=123, name=Joe}", resolver);
}
@Test returnValue = Collections.singletonMap("name", "Joe");
public void viewNameWithMultipleResolvers() throws Exception { returnType = ResolvableType.forClass(Map.class);
String value = "profile"; testHandle("/account", handler, returnValue, returnType, "account: {id=123, name=Joe}", resolver);
handle("/path", value, "handleString",
new TestViewResolver("account"), new TestViewResolver("profile"));
TestSubscriber.subscribe(this.response.getBody()) HandlerMethod hm = handlerMethod(new TestController(), "modelAttributeMethod");
.assertValuesWith(buf -> assertEquals("profile: {id=123}", returnValue = "Joe";
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8")))); returnType = ResolvableType.forMethodParameter(hm.getReturnType());
} testHandle("/account", hm, returnValue, returnType, "account: {id=123, name=Joe}", resolver);
@Test returnValue = new TestBean("Joe");
public void viewNameUnresolved() throws Exception { returnType = ResolvableType.forClass(TestBean.class);
handle("/path", "account", "handleString") testHandle("/account", handler, returnValue, returnType, "account: {id=123, testBean=TestBean[name=Joe]}", resolver);
.assertErrorMessage("Could not resolve view with name 'account'.");
} }
@Test @Test
public void viewNameIsNull() throws Exception { public void handleWithMultipleResolvers() throws Exception {
ViewResolver resolver = new TestViewResolver("account"); Object handler = new Object();
Object returnValue = "profile";
ResolvableType returnType = ResolvableType.forClass(String.class);
ViewResolver[] resolvers = {new TestViewResolver("account"), new TestViewResolver("profile")};
handle("/account", null, "handleString", resolver); testHandle("/account", handler, returnValue, returnType, "profile: {id=123}", resolvers);
TestSubscriber.subscribe(this.response.getBody())
.assertValuesWith(buf -> assertEquals("account: {id=123}",
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8"))));
handle("/account/", null, "handleString", resolver);
TestSubscriber.subscribe(this.response.getBody())
.assertValuesWith(buf -> assertEquals("account: {id=123}",
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8"))));
handle("/account.123", null, "handleString", resolver);
TestSubscriber.subscribe(this.response.getBody())
.assertValuesWith(buf -> assertEquals("account: {id=123}",
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8"))));
} }
@Test @Test
public void viewNameIsEmptyMono() throws Exception { public void defaultViewName() throws Exception {
Object value = Mono.empty(); testDefaultViewName(null, ResolvableType.forClass(String.class));
handle("/account", value, "handleMonoString", new TestViewResolver("account")); testDefaultViewName(Mono.empty(), ResolvableType.forClassWithGenerics(Mono.class, String.class));
TestSubscriber.subscribe(this.response.getBody())
.assertValuesWith(buf -> assertEquals("account: {id=123}",
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8"))));
} }
@Test private void testDefaultViewName(Object returnValue, ResolvableType returnType)
public void modelReturnValue() throws Exception { throws URISyntaxException {
Model value = new ExtendedModelMap().addAttribute("name", "Joe");
handle("/account", value, "handleModel", new TestViewResolver("account"));
TestSubscriber.subscribe(this.response.getBody()) ModelMap model = new ExtendedModelMap().addAttribute("id", "123");
.assertValuesWith(buf -> assertEquals("account: {id=123, name=Joe}", HandlerResult result = new HandlerResult(new Object(), returnValue, returnType, model);
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8")))); ViewResolutionResultHandler handler = createResultHandler(new TestViewResolver("account"));
}
@Test
public void mapReturnValue() throws Exception {
Map<String, String> value = Collections.singletonMap("name", "Joe");
handle("/account", value, "handleMap", new TestViewResolver("account"));
TestSubscriber.subscribe(this.response.getBody()) this.request.setUri(new URI("/account"));
.assertValuesWith(buf -> assertEquals("account: {id=123, name=Joe}", handler.handleResult(this.exchange, result).block(Duration.ofSeconds(5));
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8")))); assertResponseBody("account: {id=123}");
}
@Test this.request.setUri(new URI("/account/"));
public void modelAttributeAnnotationReturnValue() throws Exception { handler.handleResult(this.exchange, result).block(Duration.ofSeconds(5));
String value = "Joe"; assertResponseBody("account: {id=123}");
handle("/account", value, "handleModelAttributeAnnotation", new TestViewResolver("account"));
TestSubscriber.subscribe(this.response.getBody()) this.request.setUri(new URI("/account.123"));
.assertValuesWith(buf -> assertEquals("account: {id=123, name=Joe}", handler.handleResult(this.exchange, result).block(Duration.ofSeconds(5));
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8")))); assertResponseBody("account: {id=123}");
} }
@Test @Test
public void objectReturnValue() throws Exception { public void unresolvedViewName() throws Exception {
Object value = new TestBean("Joe"); String returnValue = "account";
handle("/account", value, "handleTestBean", new TestViewResolver("account")); ResolvableType returnType = ResolvableType.forClass(String.class);
ExtendedModelMap model = new ExtendedModelMap();
HandlerResult handlerResult = new HandlerResult(new Object(), returnValue, returnType, model);
TestSubscriber.subscribe(this.response.getBody()) this.request.setUri(new URI("/path"));
.assertValuesWith(buf -> assertEquals("account: {id=123, testBean=TestBean[name=Joe]}", Mono<Void> mono = createResultHandler().handleResult(this.exchange, handlerResult);
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8"))));
TestSubscriber.subscribe(mono).assertErrorMessage("Could not resolve view with name 'account'.");
} }
@Test @Test
public void contentNegotiation() throws Exception { public void contentNegotiation() throws Exception {
TestView htmlView = new TestView("account"); TestBean value = new TestBean("Joe");
htmlView.setMediaTypes(Collections.singletonList(MediaType.TEXT_HTML)); ResolvableType type = ResolvableType.forClass(TestBean.class);
HandlerResult handlerResult = new HandlerResult(new Object(), value, type, new ExtendedModelMap());
TestView jsonView = new TestView("defaultView"); this.request.getHeaders().setAccept(Collections.singletonList(APPLICATION_JSON));
jsonView.setMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON)); this.request.setUri(new URI("/account"));
this.request.getHeaders().setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); TestView defaultView = new TestView("jsonView", APPLICATION_JSON);
handle("/account", "account", "handleString", createResultHandler(Collections.singletonList(defaultView), new TestViewResolver("account"))
Collections.singletonList(new TestViewResolver(htmlView)), .handleResult(this.exchange, handlerResult)
Collections.singletonList(jsonView)); .block(Duration.ofSeconds(5));
assertEquals(MediaType.APPLICATION_JSON, this.response.getHeaders().getContentType()); assertEquals(APPLICATION_JSON, this.response.getHeaders().getContentType());
TestSubscriber.subscribe(this.response.getBody()) assertResponseBody("jsonView: {testBean=TestBean[name=Joe]}");
.assertValuesWith(buf -> assertEquals("defaultView: {id=123}",
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8"))));
} }
@Test @Test
public void contentNegotiationNotAcceptable() throws Exception { public void contentNegotiationWith406() throws Exception {
TestView htmlView = new TestView("account"); TestBean value = new TestBean("Joe");
htmlView.setMediaTypes(Collections.singletonList(MediaType.TEXT_HTML)); ResolvableType type = ResolvableType.forClass(TestBean.class);
HandlerResult handlerResult = new HandlerResult(new Object(), value, type, new ExtendedModelMap());
this.request.getHeaders().setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); this.request.getHeaders().setAccept(Collections.singletonList(APPLICATION_JSON));
this.request.setUri(new URI("/account"));
handle("/account", "account", "handleString", new TestViewResolver(htmlView)) ViewResolutionResultHandler resultHandler = createResultHandler(new TestViewResolver("account"));
.assertError(NotAcceptableStatusException.class); Mono<Void> mono = resultHandler.handleResult(this.exchange, handlerResult);
TestSubscriber.subscribe(mono).assertError(NotAcceptableStatusException.class);
}
private void testSupports(String methodName, boolean supports) throws NoSuchMethodException {
Method method = TestController.class.getMethod(methodName);
ResolvableType returnType = ResolvableType.forMethodParameter(method, -1);
HandlerResult result = new HandlerResult(new Object(), null, returnType, this.model);
List<ViewResolver> resolvers = Collections.singletonList(mock(ViewResolver.class));
ConfigurableConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new ReactiveStreamsToRxJava1Converter());
ViewResolutionResultHandler handler = new ViewResolutionResultHandler(resolvers, conversionService);
if (supports) {
assertTrue(handler.supports(result));
}
else {
assertFalse(handler.supports(result));
}
} }
private TestSubscriber<Void> handle(String path, Object value, String methodName,
ViewResolver... resolvers) throws Exception {
return handle(path, value, methodName, Arrays.asList(resolvers), Collections.emptyList()); private ViewResolutionResultHandler createResultHandler(ViewResolver... resolvers) {
return createResultHandler(Collections.emptyList(), resolvers);
} }
private TestSubscriber<Void> handle(String path, Object value, String methodName, private ViewResolutionResultHandler createResultHandler(List<View> defaultViews, ViewResolver... resolvers) {
List<ViewResolver> resolvers, List<View> defaultViews) throws Exception { ConfigurableConversionService service = new DefaultConversionService();
service.addConverter(new ReactiveStreamsToRxJava1Converter());
ConversionService conversionService = new DefaultConversionService(); List<ViewResolver> resolverList = Arrays.asList(resolvers);
ViewResolutionResultHandler handler = new ViewResolutionResultHandler(resolvers, conversionService); ViewResolutionResultHandler handler = new ViewResolutionResultHandler(resolverList, service);
handler.setDefaultViews(defaultViews); handler.setDefaultViews(defaultViews);
return handler;
}
private HandlerMethod handlerMethod(Object controller, String method) throws NoSuchMethodException {
return new HandlerMethod(controller, controller.getClass().getMethod(method));
}
Method method = TestController.class.getMethod(methodName); private void testHandle(String path, Object handler, Object returnValue, ResolvableType returnType,
HandlerMethod handlerMethod = new HandlerMethod(new TestController(), method); String responseBody, ViewResolver... resolvers) throws URISyntaxException {
ResolvableType type = ResolvableType.forMethodReturnType(method);
HandlerResult handlerResult = new HandlerResult(handlerMethod, value, type, this.model);
ModelMap model = new ExtendedModelMap().addAttribute("id", "123");
HandlerResult result = new HandlerResult(handler, returnValue, returnType, model);
this.request.setUri(new URI(path)); this.request.setUri(new URI(path));
WebSessionManager sessionManager = new DefaultWebSessionManager(); createResultHandler(resolvers).handleResult(this.exchange, result).block(Duration.ofSeconds(5));
ServerWebExchange exchange = new DefaultServerWebExchange(this.request, this.response, sessionManager); assertResponseBody(responseBody);
}
Mono<Void> mono = handler.handleResult(exchange, handlerResult);
return TestSubscriber.subscribe(mono).await(Duration.ofSeconds(1)); private void assertResponseBody(String responseBody) {
TestSubscriber.subscribe(this.response.getBody())
.assertValuesWith(buf -> assertEquals(responseBody,
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8"))));
} }
@ -330,10 +291,6 @@ public class ViewResolutionResultHandlerTests {
Arrays.stream(viewNames).forEach(name -> this.views.put(name, new TestView(name))); Arrays.stream(viewNames).forEach(name -> this.views.put(name, new TestView(name)));
} }
public TestViewResolver(TestView... views) {
Arrays.stream(views).forEach(view -> this.views.put(view.getName(), view));
}
public void setOrder(int order) { public void setOrder(int order) {
this.order = order; this.order = order;
} }
@ -355,19 +312,21 @@ public class ViewResolutionResultHandlerTests {
private final String name; private final String name;
private List<MediaType> mediaTypes = Collections.singletonList(MediaType.TEXT_PLAIN); private final List<MediaType> mediaTypes;
public TestView(String name) { public TestView(String name) {
this.name = name; this.name = name;
this.mediaTypes = Collections.singletonList(MediaType.TEXT_HTML);
} }
public String getName() { public TestView(String name, MediaType... mediaTypes) {
return this.name; this.name = name;
this.mediaTypes = Arrays.asList(mediaTypes);
} }
public void setMediaTypes(List<MediaType> mediaTypes) { public String getName() {
this.mediaTypes = mediaTypes; return this.name;
} }
@Override @Override
@ -389,53 +348,13 @@ public class ViewResolutionResultHandlerTests {
} }
} }
@SuppressWarnings("unused") @Controller @SuppressWarnings("unused")
private static class TestController { private static class TestController {
public String handleString() {
return null;
}
public Mono<String> handleMonoString() {
return null;
}
public Single<String> handleSingleString() {
return null;
}
public View handleView() {
return null;
}
public Mono<View> handleMonoView() {
return null;
}
public Single<View> handleSingleView() {
return null;
}
public Model handleModel() {
return null;
}
public Map<String, String> handleMap() {
return null;
}
@ModelAttribute("name") @ModelAttribute("name")
public String handleModelAttributeAnnotation() { public String modelAttributeMethod() {
return null;
}
public TestBean handleTestBean() {
return null; return null;
} }
public int handleInteger() {
return 0;
}
} }
private static class TestBean { private static class TestBean {

Loading…
Cancel
Save