Apply global ResultHandlers before ResultMatchers in MockMvc

Prior to this commit, MockMvc applied global ResultMatchers before
global ResultHandlers. This lead to unexpected scenarios where a
failing matcher would prevent a handler from being applied.

One concrete use case is `alwaysDo(print(System.err))` which should
print out MockMvc results for debugging purposes. However, if MockMvc is
configured with something like `alwaysExpect(content().string("?"))`
and the expectation fails, the user will never see the expected debug
output to help diagnose the problem.

This commit addresses this issue by applying global ResultHandlers
before ResultMatchers in MockMvc.

Closes gh-27225
This commit is contained in:
Sam Brannen 2021-07-29 19:18:18 +02:00
parent e4b9b1fadb
commit 881fa889fc
2 changed files with 99 additions and 4 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@ -217,12 +217,12 @@ public final class MockMvc {
}
private void applyDefaultResultActions(MvcResult mvcResult) throws Exception {
for (ResultMatcher matcher : this.defaultResultMatchers) {
matcher.match(mvcResult);
}
for (ResultHandler handler : this.defaultResultHandlers) {
handler.handle(mvcResult);
}
for (ResultMatcher matcher : this.defaultResultMatchers) {
matcher.match(mvcResult);
}
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright 2002-2021 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
*
* https://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.samples.standalone.resulthandlers;
import java.io.StringWriter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test;
import org.springframework.test.web.servlet.result.PrintingResultHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
/**
* Integration tests for {@link PrintingResultHandler}.
*
* @author Sam Brannen
* @author Rossen Stoyanchev
* @since 5.3.10
* @see PrintingResultHandlerSmokeTests
* @see org.springframework.test.web.servlet.result.PrintingResultHandlerTests
*/
class PrintingResultHandlerIntegrationTests {
@Test
void printMvcResultsToWriter() throws Exception {
StringWriter writer = new StringWriter();
standaloneSetup(new SimpleController())
.alwaysDo(print(writer))
.build()
.perform(get("/").content("Hello Request".getBytes()).characterEncoding("ISO-8859-1"))
.andExpect(content().string("Hello Response"));
assertThat(writer).asString()
.contains("Hello Request")
.contains("Hello Response")
.contains("Headers = [Set-Cookie:\"enigma=42\", Content-Type:\"text/plain;charset=ISO-8859-1\", Content-Length:\"14\"]");
}
@Test
void printMvcResultsToWriterWithFailingGlobalResultMatcher() throws Exception {
StringWriter writer = new StringWriter();
try {
standaloneSetup(new SimpleController())
.alwaysDo(print(writer))
.alwaysExpect(content().string("Boom!"))
.build()
.perform(get("/").content("Hello Request".getBytes()).characterEncoding("ISO-8859-1"));
}
catch (AssertionError error) {
assertThat(error).hasMessageContaining("Boom!");
}
assertThat(writer).asString()
.contains("Hello Request")
.contains("Hello Response")
.contains("Headers = [Set-Cookie:\"enigma=42\", Content-Type:\"text/plain;charset=ISO-8859-1\", Content-Length:\"14\"]");
}
@RestController
private static class SimpleController {
@GetMapping("/")
String hello(HttpServletResponse response) {
response.addCookie(new Cookie("enigma", "42"));
return "Hello Response";
}
}
}