Java tutorial
/* * Copyright 2002-2011 the original author or authors, or Red-Black IT Ltd, as appropriate. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.redblackit.web.server.mvc; import java.lang.reflect.Method; import java.net.URI; import java.net.URL; import java.util.Arrays; import java.util.List; import javax.servlet.http.HttpServletRequest; import org.apache.log4j.Logger; import org.easymock.EasyMock; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.springframework.core.MethodParameter; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import com.redblackit.web.server.mvc.annotation.RequestUrl; import org.springframework.web.method.support.ModelAndViewContainer; /** * Test class for RequestUrlArgumentResolver, verifying correct parameter * objects are returned for supported parameter types * * @author Dominic North * */ @RunWith(Parameterized.class) public class RequestUrlHandlerMethodArgumentResolverTest { /** * Interface for test classes */ interface TestController<PARMTYPE> { void methodParameter0of1(PARMTYPE requestUrl); void methodParameter1of3(int someInt, PARMTYPE requestUrl, Model model); }; /** * Class used to test with un-annotated UrlChildLocation parameter * * @author djnorth */ static private class RequestUrlHelperParameterController implements TestController<UrlChildLocation> { public void methodParameter0of1(UrlChildLocation urlChildLocation) { } public void methodParameter1of3(int someInt, UrlChildLocation urlChildLocation, Model model) { } }; /** * Class used to test with annotated UrlChildLocation parameter * * @author djnorth */ static private class AnnotatedRequestUrlHelperParameterController implements TestController<UrlChildLocation> { public void methodParameter0of1(@RequestUrl UrlChildLocation requestUrl) { } public void methodParameter1of3(int someInt, @RequestUrl UrlChildLocation requestUrl, Model model) { } }; /** * Class used to test with annotated String parameter * * @author djnorth */ static private class AnnotatedStringParameterController implements TestController<String> { public void methodParameter0of1(@RequestUrl String requestUrl) { } public void methodParameter1of3(int someInt, @RequestUrl String requestUrl, Model model) { } }; /** * Class used to test with annotated StringBuffer parameter * * @author djnorth */ static private class AnnotatedStringBufferParameterController implements TestController<StringBuffer> { public void methodParameter0of1(@RequestUrl StringBuffer requestUrl) { } public void methodParameter1of3(int someInt, @RequestUrl StringBuffer requestUrl, Model model) { } }; /** * Class used to test with annotated StringBuilder parameter * * @author djnorth */ static private class AnnotatedStringBuilderParameterController implements TestController<StringBuilder> { public void methodParameter0of1(@RequestUrl StringBuilder requestUrl) { } public void methodParameter1of3(int someInt, @RequestUrl StringBuilder requestUrl, Model model) { } }; /** * Class used to test with annotated URL parameter * * @author djnorth */ static private class AnnotatedURLParameterController implements TestController<URL> { public void methodParameter0of1(@RequestUrl URL requestUrl) { } public void methodParameter1of3(int someInt, @RequestUrl URL requestUrl, Model model) { } }; /** * Class used to test with annotated URI parameter * * @author djnorth */ static private class AnnotatedURIParameterController implements TestController<URI> { public void methodParameter0of1(@RequestUrl URI requestUrl) { } public void methodParameter1of3(int someInt, @RequestUrl URI requestUrl, Model model) { } }; /** * Class used to test with annotated Integer parameter (bad!!!) * * @author djnorth */ static private class AnnotatedIntegerParameterController implements TestController<Integer> { public void methodParameter0of1(@RequestUrl Integer requestUrl) { } public void methodParameter1of3(int someInt, @RequestUrl Integer requestUrl, Model model) { } }; /** * Class used to test with non-annotated String parameter (OK) * * @author djnorth */ static private class NonAnnotatedStringParameterController implements TestController<String> { public void methodParameter0of1(String requestUrl) { } public void methodParameter1of3(int someInt, String requestUrl, Model model) { } }; /** * Class used to test with non-annotated Integer parameter (OK) * * @author djnorth */ static private class NonAnnotatedIntegerParameterController implements TestController<Integer> { public void methodParameter0of1(Integer requestUrl) { } public void methodParameter1of3(int someInt, Integer requestUrl, Model model) { } }; /** * Test parameter creation */ @Parameters public static List<Object[]> getParameters() throws Exception { final String url0 = "https://test.com/url0"; final String url1 = "https://test.com:8443/ur10"; Object[][] parameters = { { new TestParameters(UrlChildLocation.class, true, true, url0, new UrlChildLocation(url0), new RequestUrlHelperParameterController()) }, { new TestParameters(UrlChildLocation.class, true, true, url0, new UrlChildLocation(url0), new AnnotatedRequestUrlHelperParameterController()) }, { new TestParameters(String.class, true, true, url0, url0, new AnnotatedStringParameterController()) }, { new TestParameters(StringBuffer.class, true, true, url0, url0, new AnnotatedStringBufferParameterController()) }, { new TestParameters(StringBuilder.class, true, true, url0, url0, new AnnotatedStringBuilderParameterController()) }, { new TestParameters(URL.class, true, true, url0, new URL(url0), new AnnotatedURLParameterController()) }, { new TestParameters(URI.class, true, true, url0, new URI(url0), new AnnotatedURIParameterController()) }, { new TestParameters(Integer.class, true, false, url0, url0, new AnnotatedIntegerParameterController()) }, { new TestParameters(String.class, false, true, url0, null, new NonAnnotatedStringParameterController()) }, { new TestParameters(Integer.class, false, false, url0, null, new NonAnnotatedIntegerParameterController()) }, { new TestParameters(UrlChildLocation.class, true, true, url1, new UrlChildLocation(url1), new RequestUrlHelperParameterController()) }, { new TestParameters(UrlChildLocation.class, true, true, url1, new UrlChildLocation(url1), new AnnotatedRequestUrlHelperParameterController()) }, { new TestParameters(String.class, true, true, url1, url1, new AnnotatedStringParameterController()) }, { new TestParameters(StringBuffer.class, true, true, url1, url1, new AnnotatedStringBufferParameterController()) }, { new TestParameters(StringBuilder.class, true, true, url1, url1, new AnnotatedStringBuilderParameterController()) }, { new TestParameters(URL.class, true, true, url1, new URL(url1), new AnnotatedURLParameterController()) }, { new TestParameters(URI.class, true, true, url1, new URI(url1), new AnnotatedURIParameterController()) }, { new TestParameters(Integer.class, true, false, url1, url1, new AnnotatedIntegerParameterController()) }, { new TestParameters(String.class, false, true, url1, null, new NonAnnotatedStringParameterController()) }, { new TestParameters(Integer.class, false, false, url1, null, new NonAnnotatedIntegerParameterController()) } }; return Arrays.asList(parameters); } /** * Logger */ private final Logger logger = Logger.getLogger("web.server"); /** * Test parameters */ private TestParameters testParameters; /** * WebRequest for tests */ protected NativeWebRequest nativeWebRequest; /** * Wrapped HttpServletRequest */ protected HttpServletRequest httpServletRequest; /** * Object under test */ private RequestUrlHandlerMethodArgumentResolver resolver; /** * Mock ModelAndViewContainer */ private ModelAndViewContainer mavContainer; /** * Mock WebDataBinderFactory */ private WebDataBinderFactory webDataBinderFactory; /** * @param testParameters */ public RequestUrlHandlerMethodArgumentResolverTest(TestParameters testParameters) { super(); this.testParameters = testParameters; this.resolver = new RequestUrlHandlerMethodArgumentResolver(); } /** * Setup our mocks */ @Before public void setupMocks() { httpServletRequest = EasyMock.createMock(HttpServletRequest.class); nativeWebRequest = EasyMock.createMock(NativeWebRequest.class); webDataBinderFactory = EasyMock.createMock(WebDataBinderFactory.class); if (testParameters.isParameterSupported() && testParameters.isParameterTypeValid()) { EasyMock.expect(httpServletRequest.getRequestURL()) .andReturn(new StringBuffer(testParameters.requestUrl)); EasyMock.expect(nativeWebRequest.getNativeRequest(HttpServletRequest.class)) .andReturn(httpServletRequest); } EasyMock.replay(httpServletRequest, nativeWebRequest, webDataBinderFactory); mavContainer = new ModelAndViewContainer(); } /** * Test call using parameter 0 * * Test method for * {@link com.redblackit.web.server.mvc.RequestUrlHandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory)} */ @Test public void testResolveArgumentParm0of1() throws Exception { Method method = null; try { method = testParameters.testController.getClass().getMethod("methodParameter0of1", testParameters.parameterType); } catch (NoSuchMethodException nsme) { logger.fatal(assertMsg("controller method", null)); throw nsme; } verifyParameter(method, 0); } /** * Test call using parameter 1 * * Test method for * {@link com.redblackit.web.server.mvc.RequestUrlHandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory)} */ @Test public void testResolveArgumentParm1of3() throws Exception { Method method = null; try { method = testParameters.testController.getClass().getMethod("methodParameter1of3", Integer.TYPE, testParameters.parameterType, Model.class); } catch (NoSuchMethodException nsme) { logger.fatal(assertMsg("controller method", null)); throw nsme; } verifyParameter(method, 1); } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("RequestUrlHandlerMethodArgumentResolverTest"); sb.append("{resolver=").append(resolver); sb.append(", mavContainer=").append(mavContainer); sb.append(", webDataBinderFactory=").append(webDataBinderFactory); sb.append(", testParameters=").append(testParameters); sb.append(", nativeWebRequest=").append(nativeWebRequest); sb.append(", httpServletRequest=").append(httpServletRequest); sb.append('}'); return sb.toString(); } /** * Common method for validating method under test * * @param method * @param index * @throws Exception */ protected void verifyParameter(Method method, int index) throws Exception { MethodParameter methodParameter = new MethodParameter(method, index); Object parameterValue = null; try { parameterValue = invokeResolveArgument(methodParameter); if (testParameters.isParameterSupported()) { Assert.assertTrue(assertMsg("invalid parameter type on supported parameter should cause exception", parameterValue), testParameters.isParameterTypeValid()); } if (testParameters.getExpectedParameterValue() == null) { Assert.assertNull(assertMsg("unresolved parameter value", parameterValue), parameterValue); } else { Assert.assertEquals(assertMsg("parameter type", parameterValue), testParameters.getExpectedParameterType(), parameterValue.getClass()); if (testParameters.getExpectedParameterValue() instanceof String && !(parameterValue instanceof String)) { // Sadly the inventors of Java did not implement equals for // either // StringBuffer or StringBuilder (grrrh !!!!) Assert.assertEquals(assertMsg("parameter value", parameterValue), testParameters.expectedParameterValue, parameterValue.toString()); } else { Assert.assertEquals(assertMsg("parameter value", parameterValue), testParameters.getExpectedParameterValue(), parameterValue); } } verifyExpectations(parameterValue); } catch (IllegalStateException ise) { if (testParameters.parameterTypeValid) { logger.fatal(assertMsg("exception on valid parameter type", null)); verifyExpectations(parameterValue); throw ise; } else { logger.trace(assertMsg("expected exception on invalid parameter type", null), ise); verifyExpectations(parameterValue); } } } /** * Helper to add context to assertion message * * @param msg to enhance * @param parameterValue * @return result */ protected String assertMsg(String msg, Object parameterValue) { StringBuilder sb = new StringBuilder(msg); sb.append(":parameterValue=").append(parameterValue); if (parameterValue != null) { sb.append(" (").append(parameterValue.getClass()).append(')'); } sb.append(':').append(this); return sb.toString(); } /** * @return the nativeWebRequest */ protected NativeWebRequest getNativeWebRequest() { return nativeWebRequest; } /** * @return the httpServletRequest */ protected HttpServletRequest getHttpServletRequest() { return httpServletRequest; } /** * @return the logger */ protected Logger getLogger() { return logger; } /** * Verify expectations in EasyMock * * @param parameterValue */ private void verifyExpectations(Object parameterValue) { EasyMock.verify(httpServletRequest, nativeWebRequest); ModelMap modelMap = mavContainer.getModel(); Assert.assertEquals(assertMsg("modelAndViewContainer.modelMap.size()", parameterValue), 0, modelMap.size()); Assert.assertNull(assertMsg("modelAndViewContainer.getView() should be null", parameterValue), mavContainer.getView()); Assert.assertNull(assertMsg("modelAndViewContainer.getViewName() should be null", parameterValue), mavContainer.getViewName()); EasyMock.verify(webDataBinderFactory); } /** * Invoke our HandlerMethodArgumentResolver * * @param methodParameter * @return parameter object * @throws Exception */ private Object invokeResolveArgument(MethodParameter methodParameter) throws Exception { return resolver.resolveArgument(methodParameter, mavContainer, getNativeWebRequest(), webDataBinderFactory); } /** * Test parameter encapsulation class * * @author djnorth */ static final class TestParameters { /** * Type for parameter */ private final Class<?> parameterType; /** * Parameter is supported (or not) */ private final boolean parameterSupported; /** * Parameter type is valid (or not) */ private final boolean parameterTypeValid; /** * Expected value for requestUrl */ private final String requestUrl; /** * Expected value for parameter */ private final Object expectedParameterValue; /** * testController with whose methods we test */ private final TestController<?> testController; /** * @param parameterType * @param requestUrl * @param expectedParameterValue * @param parameterSupported * @param parameterTypeValid * @param testController */ public TestParameters(Class<?> parameterType, boolean parameterSupported, boolean parameterTypeValid, String requestUrl, Object expectedParameterValue, TestController<?> testController) { super(); this.parameterType = parameterType; this.requestUrl = requestUrl; this.expectedParameterValue = expectedParameterValue; this.parameterSupported = parameterSupported; this.parameterTypeValid = parameterTypeValid; this.testController = testController; } /** * @return the expectedParameterType */ public Class<?> getExpectedParameterType() { return parameterType; } /** * @return the expectedParameterValue */ public Object getExpectedParameterValue() { return expectedParameterValue; } /** * @return the parameterSupported */ public boolean isParameterSupported() { return parameterSupported; } /** * @return the parameterTypeValid */ public boolean isParameterTypeValid() { return parameterTypeValid; } /** * @return the testController */ public TestController<?> getTestController() { return testController; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("RequestResponseParameters [expectedParameterType="); builder.append(parameterType); builder.append(", requestUrl="); builder.append(requestUrl); builder.append(", expectedParameterValue="); builder.append(expectedParameterValue); builder.append(", parameterSupported="); builder.append(parameterSupported); builder.append(", parameterTypeValid="); builder.append(parameterTypeValid); builder.append(", testController="); builder.append(testController); builder.append("]"); return builder.toString(); } } }