diff --git a/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/result/HeaderResultMatchers.java b/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/result/HeaderResultMatchers.java index 5e0f5b2a1d5..0fef4e43fd5 100644 --- a/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/result/HeaderResultMatchers.java +++ b/spring-test-mvc/src/main/java/org/springframework/test/web/servlet/result/HeaderResultMatchers.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 static org.springframework.test.util.MatcherAssertionErrors.assertThat; import org.hamcrest.Matcher; @@ -28,6 +29,7 @@ import org.springframework.test.web.servlet.ResultMatcher; * class is usually accessed via {@link MockMvcResultMatchers#header()}. * * @author Rossen Stoyanchev + * @author Sam Brannen * @since 3.2 */ public class HeaderResultMatchers { @@ -41,36 +43,45 @@ public class HeaderResultMatchers { } /** - * Assert a response header with the given Hamcrest {@link Matcher}. + * Assert the primary value of the named response header with the given + * Hamcrest {@link Matcher}. */ public ResultMatcher string(final String name, final Matcher matcher) { return new ResultMatcher() { + @Override public void match(MvcResult result) { - assertThat("Response header", result.getResponse().getHeader(name), matcher); + assertThat("Response header " + name, result.getResponse().getHeader(name), matcher); } }; } /** - * Assert the primary value of a response header as a {@link String}. + * Assert the primary value of the named response header as a {@link String}. */ public ResultMatcher string(final String name, final String value) { return new ResultMatcher() { + @Override public void match(MvcResult result) { - assertEquals("Response header", value, result.getResponse().getHeader(name)); + assertEquals("Response header " + name, value, result.getResponse().getHeader(name)); } }; } /** - * Assert the primary value of a response header as a {@link Long}. + * Assert the primary value of the named response header as a {@code long}. + * + *

The {@link ResultMatcher} returned by this method throws an {@link AssertionError} + * if the response does not contain the specified header, or if the supplied + * {@code value} does not match the primary value. */ public ResultMatcher longValue(final String name, final long value) { return new ResultMatcher() { + @Override public void match(MvcResult result) { + assertTrue("Response does not contain header " + name, result.getResponse().containsHeader(name)); assertEquals("Response header " + name, value, Long.parseLong(result.getResponse().getHeader(name))); } }; diff --git a/spring-test-mvc/src/test/java/org/springframework/test/web/servlet/samples/standalone/resultmatchers/HeaderAssertionTests.java b/spring-test-mvc/src/test/java/org/springframework/test/web/servlet/samples/standalone/resultmatchers/HeaderAssertionTests.java index d8bfe0c7802..1a3f56771c1 100644 --- a/spring-test-mvc/src/test/java/org/springframework/test/web/servlet/samples/standalone/resultmatchers/HeaderAssertionTests.java +++ b/spring-test-mvc/src/test/java/org/springframework/test/web/servlet/samples/standalone/resultmatchers/HeaderAssertionTests.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. @@ -16,72 +16,154 @@ package org.springframework.test.web.servlet.samples.standalone.resultmatchers; -import static org.hamcrest.Matchers.nullValue; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - -import java.util.Date; - import org.junit.Before; import org.junit.Test; import org.springframework.stereotype.Controller; import org.springframework.test.web.Person; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultMatcher; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.context.request.WebRequest; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*; + /** * Examples of expectations on response header values. - * + * * @author Rossen Stoyanchev + * @author Sam Brannen */ public class HeaderAssertionTests { + private static final String EXPECTED_ASSERTION_ERROR_MSG = "Should have thrown an AssertionError"; + + private static final String IF_MODIFIED_SINCE = "If-Modified-Since"; + + private static final String LAST_MODIFIED = "Last-Modified"; + + private final long currentTime = System.currentTimeMillis(); + private MockMvc mockMvc; private PersonController personController; + @Before public void setup() { this.personController = new PersonController(); + this.personController.setStubTimestamp(currentTime); this.mockMvc = standaloneSetup(this.personController).build(); } @Test - public void testValue() throws Exception { - long currentTime = new Date().getTime(); - this.personController.setStubTimestamp(currentTime); - this.mockMvc.perform(get("/persons/1").header("If-Modified-Since", currentTime - (1000 * 60))) - .andExpect(header().string("Last-Modified", String.valueOf(currentTime))); + public void stringWithCorrectResponseHeaderValue() throws Exception { + this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, currentTime - (1000 * 60)))// + .andExpect(header().string(LAST_MODIFIED, String.valueOf(currentTime))); } @Test - public void testLongValue() throws Exception { - long currentTime = new Date().getTime(); - this.personController.setStubTimestamp(currentTime); - this.mockMvc.perform(get("/persons/1").header("If-Modified-Since", currentTime - (1000 * 60))) - .andExpect(header().longValue("Last-Modified", currentTime)); + public void stringWithMatcherAndCorrectResponseHeaderValue() throws Exception { + this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, currentTime - (1000 * 60)))// + .andExpect(header().string(LAST_MODIFIED, equalTo(String.valueOf(currentTime)))); } @Test - public void testMatcher() throws Exception { - long currentTime = new Date().getTime(); - this.personController.setStubTimestamp(currentTime); - this.mockMvc.perform(get("/persons/1").header("If-Modified-Since", currentTime)) - .andExpect(status().isNotModified()) - .andExpect(header().string("Last-Modified", nullValue())); + public void longValueWithCorrectResponseHeaderValue() throws Exception { + this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, currentTime - (1000 * 60)))// + .andExpect(header().longValue(LAST_MODIFIED, currentTime)); + } + + @Test + public void stringWithMissingResponseHeader() throws Exception { + this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, currentTime))// + .andExpect(status().isNotModified())// + .andExpect(header().string(LAST_MODIFIED, (String) null)); } + @Test + public void stringWithMatcherAndMissingResponseHeader() throws Exception { + this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, currentTime))// + .andExpect(status().isNotModified())// + .andExpect(header().string(LAST_MODIFIED, nullValue())); + } + + @Test + public void longValueWithMissingResponseHeader() throws Exception { + try { + this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, currentTime))// + .andExpect(status().isNotModified())// + .andExpect(header().longValue(LAST_MODIFIED, 99L)); + + fail(EXPECTED_ASSERTION_ERROR_MSG); + } + catch (AssertionError e) { + if (EXPECTED_ASSERTION_ERROR_MSG.equals(e.getMessage())) { + throw e; + } + assertEquals("Response does not contain header " + LAST_MODIFIED, e.getMessage()); + } + } + + @Test + public void stringWithIncorrectResponseHeaderValue() throws Exception { + long unexpected = currentTime + 1; + assertIncorrectResponseHeaderValue(header().string(LAST_MODIFIED, String.valueOf(unexpected)), unexpected); + } + + @Test + public void stringWithMatcherAndIncorrectResponseHeaderValue() throws Exception { + long unexpected = currentTime + 1; + assertIncorrectResponseHeaderValue(header().string(LAST_MODIFIED, equalTo(String.valueOf(unexpected))), + unexpected); + } + + @Test + public void longValueWithIncorrectResponseHeaderValue() throws Exception { + long unexpected = currentTime + 1; + assertIncorrectResponseHeaderValue(header().longValue(LAST_MODIFIED, unexpected), unexpected); + } + + private void assertIncorrectResponseHeaderValue(ResultMatcher resultMatcher, long unexpected) throws Exception { + try { + this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, currentTime - (1000 * 60)))// + .andExpect(resultMatcher); + + fail(EXPECTED_ASSERTION_ERROR_MSG); + } + catch (AssertionError e) { + if (EXPECTED_ASSERTION_ERROR_MSG.equals(e.getMessage())) { + throw e; + } + // [SPR-10659] Ensure that the header name is included in the message + // + // We don't use assertEquals() since we cannot control the formatting + // produced by JUnit or Hamcrest. + assertMessageContains(e, "Response header " + LAST_MODIFIED); + assertMessageContains(e, String.valueOf(unexpected)); + assertMessageContains(e, String.valueOf(currentTime)); + } + } + + private void assertMessageContains(AssertionError error, String expected) { + String message = error.getMessage(); + assertTrue("Failure message should contain: " + expected, message.contains(expected)); + } + + + // ------------------------------------------------------------------------- @Controller private static class PersonController { private long timestamp; + public void setStubTimestamp(long timestamp) { this.timestamp = timestamp; }