Polish HeaderResultMatchers

This commit is contained in:
Rossen Stoyanchev 2016-01-21 10:11:37 -05:00
parent 18db77da7c
commit ae224bed3e
2 changed files with 85 additions and 78 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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,6 +18,7 @@ package org.springframework.test.web.servlet.result;
import org.hamcrest.Matcher;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher;
@ -31,7 +32,7 @@ import java.util.TimeZone;
/**
* Factory for response header assertions.
* <p>An instance of this class is usually accessed via
* <p>An instance of this class is available via
* {@link MockMvcResultMatchers#header}.
*
* @author Rossen Stoyanchev
@ -41,13 +42,15 @@ import java.util.TimeZone;
*/
public class HeaderResultMatchers {
/**
* Protected constructor.
* Use {@link MockMvcResultMatchers#header()}.
* See {@link MockMvcResultMatchers#header()}.
*/
protected HeaderResultMatchers() {
}
/**
* Assert the primary value of the named response header with the given
* Hamcrest {@link Matcher}.
@ -81,23 +84,25 @@ public class HeaderResultMatchers {
return new ResultMatcher() {
@Override
public void match(MvcResult result) {
assertTrue("Response should not contain header " + name, !result.getResponse().containsHeader(name));
assertTrue("Response should not contain header " + name,
!result.getResponse().containsHeader(name));
}
};
}
/**
* Assert the primary value of the named response header as a {@code long}.
* <p>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.
* <p>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)));
MockHttpServletResponse response = result.getResponse();
assertTrue("Response does not contain header " + name, response.containsHeader(name));
assertEquals("Response header " + name, value, Long.parseLong(response.getHeader(name)));
}
};
}
@ -105,10 +110,9 @@ public class HeaderResultMatchers {
/**
* Assert the primary value of the named response header as a date String,
* using the preferred date format described in RFC 7231.
* <p>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.
*
* <p>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.
* @see <a href="https://tools.ietf.org/html/rfc7231#section-7.1.1.1">Section 7.1.1.1 of RFC 7231</a>
* @since 4.2
*/
@ -118,8 +122,10 @@ public class HeaderResultMatchers {
public void match(MvcResult result) {
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
assertTrue("Response does not contain header " + name, result.getResponse().containsHeader(name));
assertEquals("Response header " + name, format.format(new Date(value)), result.getResponse().getHeader(name));
String formatted = format.format(new Date(value));
MockHttpServletResponse response = result.getResponse();
assertTrue("Response does not contain header " + name, response.containsHeader(name));
assertEquals("Response header " + name, formatted, response.getHeader(name));
}
};
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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,6 +16,11 @@
package org.springframework.test.web.servlet.samples.standalone.resultmatchers;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import org.junit.Before;
import org.junit.Test;
@ -28,16 +33,18 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
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.*;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.springframework.http.HttpHeaders.IF_MODIFIED_SINCE;
import static org.springframework.http.HttpHeaders.LAST_MODIFIED;
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.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
* Examples of expectations on response header values.
@ -48,86 +55,83 @@ import java.util.TimeZone;
*/
public class HeaderAssertionTests {
private static final String EXPECTED_ASSERTION_ERROR_MSG = "Should have thrown an AssertionError";
private static final String ERROR_MESSAGE = "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 String now;
private String oneMinuteAgo;
private String minuteAgo;
private String oneSecondLater;
private String secondLater;
private MockMvc mockMvc;
private PersonController personController;
private final long currentTime = System.currentTimeMillis();
@Before
public void setup() {
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
this.now = dateFormat.format(new Date(currentTime));
this.oneMinuteAgo = dateFormat.format(new Date(currentTime - (1000 * 60)));
this.oneSecondLater = dateFormat.format(new Date(currentTime + 1000));
this.personController = new PersonController();
this.personController.setStubTimestamp(currentTime);
this.mockMvc = standaloneSetup(this.personController).build();
this.now = dateFormat.format(new Date(this.currentTime));
this.minuteAgo = dateFormat.format(new Date(this.currentTime - (1000 * 60)));
this.secondLater = dateFormat.format(new Date(this.currentTime + 1000));
PersonController controller = new PersonController();
controller.setStubTimestamp(this.currentTime);
this.mockMvc = standaloneSetup(controller).build();
}
@Test
public void stringWithCorrectResponseHeaderValue() throws Exception {
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, oneMinuteAgo))//
.andExpect(header().string(LAST_MODIFIED, now));
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo))
.andExpect(header().string(LAST_MODIFIED, now));
}
@Test
public void stringWithMatcherAndCorrectResponseHeaderValue() throws Exception {
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, oneMinuteAgo))//
.andExpect(header().string(LAST_MODIFIED, equalTo(now)));
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo))
.andExpect(header().string(LAST_MODIFIED, equalTo(now)));
}
@Test
public void dateValueWithCorrectResponseHeaderValue() throws Exception {
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, oneMinuteAgo))//
.andExpect(header().dateValue(LAST_MODIFIED, currentTime));
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo))
.andExpect(header().dateValue(LAST_MODIFIED, this.currentTime));
}
@Test
public void longValueWithCorrectResponseHeaderValue() throws Exception {
this.mockMvc.perform(get("/persons/1"))//
.andExpect(header().longValue("X-Rate-Limiting", 42));
this.mockMvc.perform(get("/persons/1"))
.andExpect(header().longValue("X-Rate-Limiting", 42));
}
@Test
public void stringWithMissingResponseHeader() throws Exception {
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, now))//
.andExpect(status().isNotModified())//
.andExpect(header().string("X-Custom-Header", (String) null));
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, now))
.andExpect(status().isNotModified())
.andExpect(header().string("X-Custom-Header", (String) null));
}
@Test
public void stringWithMatcherAndMissingResponseHeader() throws Exception {
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, now))//
.andExpect(status().isNotModified())//
.andExpect(header().string("X-Custom-Header", nullValue()));
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, now))
.andExpect(status().isNotModified())
.andExpect(header().string("X-Custom-Header", nullValue()));
}
@Test
public void longValueWithMissingResponseHeader() throws Exception {
try {
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, now))//
.andExpect(status().isNotModified())//
.andExpect(header().longValue("X-Custom-Header", 99L));
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, now))
.andExpect(status().isNotModified())
.andExpect(header().longValue("X-Custom-Header", 99L));
fail(EXPECTED_ASSERTION_ERROR_MSG);
fail(ERROR_MESSAGE);
}
catch (AssertionError e) {
if (EXPECTED_ASSERTION_ERROR_MSG.equals(e.getMessage())) {
if (ERROR_MESSAGE.equals(e.getMessage())) {
throw e;
}
assertEquals("Response does not contain header " + "X-Custom-Header", e.getMessage());
@ -138,32 +142,30 @@ public class HeaderAssertionTests {
@Test
public void doesNotExist() throws Exception {
this.mockMvc.perform(get("/persons/1"))
.andExpect(header().doesNotExist("X-Custom-Header"));
this.mockMvc.perform(get("/persons/1")).andExpect(header().doesNotExist("X-Custom-Header"));
}
// SPR-10771
@Test(expected = AssertionError.class)
public void doesNotExistFail() throws Exception {
this.mockMvc.perform(get("/persons/1"))
.andExpect(header().doesNotExist(LAST_MODIFIED));
this.mockMvc.perform(get("/persons/1")).andExpect(header().doesNotExist(LAST_MODIFIED));
}
@Test
public void stringWithIncorrectResponseHeaderValue() throws Exception {
assertIncorrectResponseHeaderValue(header().string(LAST_MODIFIED, oneSecondLater), oneSecondLater);
assertIncorrectResponseHeader(header().string(LAST_MODIFIED, secondLater), secondLater);
}
@Test
public void stringWithMatcherAndIncorrectResponseHeaderValue() throws Exception {
assertIncorrectResponseHeaderValue(header().string(LAST_MODIFIED, equalTo(oneSecondLater)), oneSecondLater);
assertIncorrectResponseHeader(header().string(LAST_MODIFIED, equalTo(secondLater)), secondLater);
}
@Test
public void dateValueWithIncorrectResponseHeaderValue() throws Exception {
long unexpected = currentTime + 1000;
assertIncorrectResponseHeaderValue(header().dateValue(LAST_MODIFIED, unexpected), oneSecondLater);
long unexpected = this.currentTime + 1000;
assertIncorrectResponseHeader(header().dateValue(LAST_MODIFIED, unexpected), secondLater);
}
@Test(expected = AssertionError.class)
@ -171,21 +173,20 @@ public class HeaderAssertionTests {
this.mockMvc.perform(get("/persons/1")).andExpect(header().longValue("X-Rate-Limiting", 1));
}
private void assertIncorrectResponseHeaderValue(ResultMatcher resultMatcher, String unexpected) throws Exception {
private void assertIncorrectResponseHeader(ResultMatcher matcher, String unexpected) throws Exception {
try {
this.mockMvc.perform(get("/persons/1").header(IF_MODIFIED_SINCE, oneMinuteAgo))//
.andExpect(resultMatcher);
this.mockMvc.perform(get("/persons/1")
.header(IF_MODIFIED_SINCE, minuteAgo))
.andExpect(matcher);
fail(EXPECTED_ASSERTION_ERROR_MSG);
fail(ERROR_MESSAGE);
}
catch (AssertionError e) {
if (EXPECTED_ASSERTION_ERROR_MSG.equals(e.getMessage())) {
if (ERROR_MESSAGE.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.
// SPR-10659: ensure header name is in the message
// Unfortunately, we can't control formatting from JUnit or Hamcrest.
assertMessageContains(e, "Response header " + LAST_MODIFIED);
assertMessageContains(e, unexpected);
assertMessageContains(e, now);
@ -198,9 +199,8 @@ public class HeaderAssertionTests {
}
// -------------------------------------------------------------------------
@Controller
@SuppressWarnings("unused")
private static class PersonController {
private long timestamp;
@ -216,6 +216,7 @@ public class HeaderAssertionTests {
.ok()
.lastModified(calculateLastModified(id))
.header("X-Rate-Limiting", "42")
.header("Vary", "foo", "bar")
.body(new Person("Jason"));
}