Use getUriTemplate of MockHttpServletRequest

Fixes gh-939
This commit is contained in:
Andy Wilkinson
2024-09-13 10:34:32 +01:00
parent 4315acfe50
commit 272ed24de8
3 changed files with 59 additions and 3 deletions

View File

@@ -802,7 +802,7 @@ Uses the static `parameterWithName` method on `org.springframework.restdocs.requ
The result is a snippet named `path-parameters.adoc` that contains a table describing the path parameters that are supported by the resource.
TIP: If you use MockMvc, to make the path parameters available for documentation, you must build the request by using one of the methods on `RestDocumentationRequestBuilders` rather than `MockMvcRequestBuilders`.
TIP: If you use MockMvc with Spring Framework 6.1 or earlier, to make the path parameters available for documentation, you must build the request by using one of the methods on `RestDocumentationRequestBuilders` rather than `MockMvcRequestBuilders`.
When documenting path parameters, the test fails if an undocumented path parameter is used in the request.
Similarly, the test also fails if a documented path parameter is not found in the request and the path parameter has not been marked as optional.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2024 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,8 +16,10 @@
package org.springframework.restdocs.mockmvc;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.restdocs.RestDocumentationContext;
@@ -27,6 +29,7 @@ import org.springframework.restdocs.generate.RestDocumentationGenerator;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.context.WebApplicationContext;
/**
@@ -85,6 +88,26 @@ public final class MockMvcRestDocumentationConfigurer extends
private final class ConfigurerApplyingRequestPostProcessor implements RequestPostProcessor {
private static final Function<MockHttpServletRequest, String> urlTemplateExtractor;
static {
Function<MockHttpServletRequest, String> fromRequestAttribute = (
request) -> (String) request.getAttribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE);
Function<MockHttpServletRequest, String> extractor;
try {
Method accessorMethod = MockHttpServletRequest.class.getMethod("getUriTemplate");
extractor = (request) -> {
String urlTemplate = fromRequestAttribute.apply(request);
return (urlTemplate != null) ? urlTemplate
: (String) ReflectionUtils.invokeMethod(accessorMethod, request);
};
}
catch (Exception ex) {
extractor = fromRequestAttribute;
}
urlTemplateExtractor = extractor;
}
private final RestDocumentationContextProvider contextManager;
private ConfigurerApplyingRequestPostProcessor(RestDocumentationContextProvider contextManager) {
@@ -97,7 +120,7 @@ public final class MockMvcRestDocumentationConfigurer extends
Map<String, Object> configuration = new HashMap<>();
configuration.put(MockHttpServletRequest.class.getName(), request);
configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE,
request.getAttribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE));
urlTemplateExtractor.apply(request));
configuration.put(RestDocumentationContext.class.getName(), context);
request.setAttribute(RestDocumentationResultHandler.ATTRIBUTE_NAME_CONFIGURATION, configuration);
MockMvcRestDocumentationConfigurer.this.apply(configuration, context);

View File

@@ -16,12 +16,18 @@
package org.springframework.restdocs.mockmvc;
import java.lang.reflect.Method;
import java.util.Map;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.generate.RestDocumentationGenerator;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
@@ -86,6 +92,33 @@ public class MockMvcRestDocumentationConfigurerTests {
assertThat(this.request.getHeader("Content-Length")).isNull();
}
@Test
@SuppressWarnings("unchecked")
public void uriTemplateFromRequestAttribute() {
RequestPostProcessor postProcessor = new MockMvcRestDocumentationConfigurer(this.restDocumentation)
.beforeMockMvcCreated(null, null);
this.request.setAttribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "{a}/{b}");
postProcessor.postProcessRequest(this.request);
Map<String, Object> configuration = (Map<String, Object>) this.request
.getAttribute(RestDocumentationResultHandler.ATTRIBUTE_NAME_CONFIGURATION);
assertThat(configuration).containsEntry(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "{a}/{b}");
}
@Test
@SuppressWarnings("unchecked")
public void uriTemplateFromRequest() {
Method setUriTemplate = ReflectionUtils.findMethod(MockHttpServletRequest.class, "setUriTemplate",
String.class);
Assume.assumeNotNull(setUriTemplate);
RequestPostProcessor postProcessor = new MockMvcRestDocumentationConfigurer(this.restDocumentation)
.beforeMockMvcCreated(null, null);
ReflectionUtils.invokeMethod(setUriTemplate, this.request, "{a}/{b}");
postProcessor.postProcessRequest(this.request);
Map<String, Object> configuration = (Map<String, Object>) this.request
.getAttribute(RestDocumentationResultHandler.ATTRIBUTE_NAME_CONFIGURATION);
assertThat(configuration).containsEntry(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, "{a}/{b}");
}
private void assertUriConfiguration(String scheme, String host, int port) {
assertThat(scheme).isEqualTo(this.request.getScheme());
assertThat(host).isEqualTo(this.request.getServerName());