From e04a7569687a4da98f1c39fbee1ff209715c3fdd Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 8 Oct 2013 10:50:51 +0200 Subject: [PATCH] Support AntPathMatch URLs in URL ResultMatchers Prior to this commit, one could only match exact URLs in redirectedUrl and forwardedUrl ResultMatchers. When creating a resource with a REST service, URLs often contain the id the new resource, like "/resource/12". This commit updates those ResultMatchers to support both exact matches and AntPath matches, using new methods. The former URL then can be tested against "/resource/*" in MVC tests. Issue: SPR-10789 --- .../servlet/result/MockMvcResultMatchers.java | 59 +++++++++++++- .../result/MockMvcResultMatchersTests.java | 77 +++++++++++++++++++ .../resultmatchers/UrlAssertionTests.java | 13 +++- 3 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 spring-test-mvc/src/test/java/org/springframework/test/web/servlet/result/MockMvcResultMatchersTests.java diff --git a/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java b/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java index 15497195981..3532bc71d20 100644 --- a/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java +++ b/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -17,6 +17,7 @@ package org.springframework.test.web.servlet.result; import static org.springframework.test.util.AssertionErrors.assertEquals; +import static org.springframework.test.util.AssertionErrors.assertTrue; import java.util.Map; @@ -25,6 +26,7 @@ import javax.xml.xpath.XPathExpressionException; import org.hamcrest.Matcher; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultMatcher; +import org.springframework.util.AntPathMatcher; /** * Static, factory methods for {@link ResultMatcher}-based result actions. @@ -33,6 +35,7 @@ import org.springframework.test.web.servlet.ResultMatcher; * favorite. To navigate, open the Preferences and type "favorites". * * @author Rossen Stoyanchev + * @author Brian Clozel * @since 3.2 */ public abstract class MockMvcResultMatchers { @@ -78,6 +81,8 @@ public abstract class MockMvcResultMatchers { /** * Asserts the request was forwarded to the given URL. + * This methods accepts only exact matches. + * @param expectedUrl the exact URL expected */ public static ResultMatcher forwardedUrl(final String expectedUrl) { return new ResultMatcher() { @@ -88,8 +93,35 @@ public abstract class MockMvcResultMatchers { }; } + /** + * Asserts the request was forwarded to the given URL. + * This methods accepts {@link org.springframework.util.AntPathMatcher} expressions. + * + *

When trying to match against "?" or "*" exactly, those characters + * should be escaped (e.g. "\\?" and "\\*") + * + * @param expectedUrl an AntPath expression to match against + * @see org.springframework.util.AntPathMatcher + * @since 4.0 + */ + public static ResultMatcher forwardedUrlPattern(final String expectedUrl) { + return new ResultMatcher() { + + private final AntPathMatcher pathMatcher = new AntPathMatcher(); + + @Override + public void match(MvcResult result) { + assertTrue("AntPath expression",pathMatcher.isPattern(expectedUrl)); + assertTrue("Forwarded URL", + pathMatcher.match(expectedUrl, result.getResponse().getForwardedUrl())); + } + }; + } + /** * Asserts the request was redirected to the given URL. + * This methods accepts only exact matches. + * @param expectedUrl the exact URL expected */ public static ResultMatcher redirectedUrl(final String expectedUrl) { return new ResultMatcher() { @@ -100,6 +132,31 @@ public abstract class MockMvcResultMatchers { }; } + /** + * Asserts the request was redirected to the given URL. + * This methods accepts {@link org.springframework.util.AntPathMatcher} expressions. + * + *

When trying to match against "?" or "*" exactly, those characters + * should be escaped (e.g. "\\?" and "\\*") + * + * @param expectedUrl an AntPath expression to match against + * @see org.springframework.util.AntPathMatcher + * @since 4.0 + */ + public static ResultMatcher redirectedUrlPattern(final String expectedUrl) { + return new ResultMatcher() { + + private final AntPathMatcher pathMatcher = new AntPathMatcher(); + + @Override + public void match(MvcResult result) { + assertTrue("AntPath expression",pathMatcher.isPattern(expectedUrl)); + assertTrue("Redirected URL", + pathMatcher.match(expectedUrl, result.getResponse().getRedirectedUrl())); + } + }; + } + /** * Access to response status assertions. */ diff --git a/spring-test-mvc/src/test/java/org/springframework/test/web/servlet/result/MockMvcResultMatchersTests.java b/spring-test-mvc/src/test/java/org/springframework/test/web/servlet/result/MockMvcResultMatchersTests.java new file mode 100644 index 00000000000..3fcf3031a91 --- /dev/null +++ b/spring-test-mvc/src/test/java/org/springframework/test/web/servlet/result/MockMvcResultMatchersTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.test.web.servlet.result; + +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.web.servlet.StubMvcResult; + +/** + * @author Brian Clozel + */ +public class MockMvcResultMatchersTests { + + @Test + public void testRedirect() throws Exception { + MockMvcResultMatchers.redirectedUrl("/resource/1") + .match(getRedirectedUrlStubMvcResult("/resource/1")); + } + + @Test + public void testRedirectPattern() throws Exception { + MockMvcResultMatchers.redirectedUrlPattern("/resource/*") + .match(getRedirectedUrlStubMvcResult("/resource/1")); + } + + @Test( expected = java.lang.AssertionError.class) + public void testFailRedirectPattern() throws Exception { + MockMvcResultMatchers.redirectedUrlPattern("/resource/") + .match(getRedirectedUrlStubMvcResult("/resource/1")); + } + + @Test + public void testForward() throws Exception { + MockMvcResultMatchers.forwardedUrl("/api/resource/1") + .match(getForwardedUrlStubMvcResult("/api/resource/1")); + } + + @Test + public void testForwardEscapedChars() throws Exception { + MockMvcResultMatchers.forwardedUrl("/api/resource/1?arg=value") + .match(getForwardedUrlStubMvcResult("/api/resource/1?arg=value")); + } + + @Test + public void testForwardPattern() throws Exception { + MockMvcResultMatchers.forwardedUrlPattern("/api/**/?") + .match(getForwardedUrlStubMvcResult("/api/resource/1")); + } + + private StubMvcResult getRedirectedUrlStubMvcResult(String redirectUrl) throws Exception { + MockHttpServletResponse response = new MockHttpServletResponse(); + response.sendRedirect(redirectUrl); + StubMvcResult mvcResult = new StubMvcResult(null, null, null, null, null, null, response); + return mvcResult; + } + + private StubMvcResult getForwardedUrlStubMvcResult(String forwardedUrl) { + MockHttpServletResponse response = new MockHttpServletResponse(); + response.setForwardedUrl(forwardedUrl); + StubMvcResult mvcResult = new StubMvcResult(null, null, null, null, null, null, response); + return mvcResult; + } + +} diff --git a/spring-test-mvc/src/test/java/org/springframework/test/web/servlet/samples/standalone/resultmatchers/UrlAssertionTests.java b/spring-test-mvc/src/test/java/org/springframework/test/web/servlet/samples/standalone/resultmatchers/UrlAssertionTests.java index 278c2cf949f..119b4c3d5db 100644 --- a/spring-test-mvc/src/test/java/org/springframework/test/web/servlet/samples/standalone/resultmatchers/UrlAssertionTests.java +++ b/spring-test-mvc/src/test/java/org/springframework/test/web/servlet/samples/standalone/resultmatchers/UrlAssertionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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,7 +18,9 @@ package org.springframework.test.web.servlet.samples.standalone.resultmatchers; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrlPattern; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern; import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; import org.junit.Before; @@ -46,11 +48,20 @@ public class UrlAssertionTests { this.mockMvc.perform(get("/persons")).andExpect(redirectedUrl("/persons/1")); } + @Test + public void testRedirectPattern() throws Exception { + this.mockMvc.perform(get("/persons")).andExpect(redirectedUrlPattern("/persons/*")); + } + @Test public void testForward() throws Exception { this.mockMvc.perform(get("/")).andExpect(forwardedUrl("/home")); } + @Test + public void testForwardPattern() throws Exception { + this.mockMvc.perform(get("/")).andExpect(forwardedUrlPattern("/ho?e")); + } @Controller private static class SimpleController {