Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ExecutingResponseCreator to delegate request and response #29721

Closed

Conversation

simonbasle
Copy link
Contributor

@simonbasle simonbasle commented Dec 20, 2022

This commit adds a new convenience ResponseCreator implementation that
delegates to a ClientHttpRequestFactory to perform a request and
use the response.

For further convenience, a factory method based on a RestTemplate is
also added: MockRestResponseCreators#byExecutingRequestUsing. This
acts as a pseudo-DSL for fluently setting the ResponseCreator in a
ResponseActions.

The primary purpose of this implementation is to perform an actual
request to an external service and use the response in MockMVC.

Closes gh-26381

This commit adds the andPerformRequest method to ResponseActions, which
is in effect activating a ResponseCreator that has been implicitly
defined for relevant implementations.

Implementations without explicit support for this will throw an
UnsupportedOperationException by default.

The SimpleRequestExpectationManager and UnorderedRequestExpectationManager
created in `MockRestServiceServerBuilder#build()` capture and use the
original ClientHttpRequestFactory, setting up an implicit ResponseCreator
that executes an actual request and returns the response.

Fixes spring-projectsgh-26381.
@simonbasle simonbasle added in: test Issues in the test module type: enhancement A general enhancement labels Dec 20, 2022
@simonbasle simonbasle requested a review from a team December 20, 2022 16:14
@rstoyanchev rstoyanchev self-assigned this Jan 3, 2023
Copy link
Contributor

@rstoyanchev rstoyanchev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for putting this together based on the discussion under #26381. Looking at the result, I'm wondering if it wouldn't be more idiomatic to simply provide a ResponseCreator implementation instead:

public class ExecutingResponseCreator implements ResponseCreator {

	private final ClientHttpRequestFactory requestFactory;


	public ExecutingResponseCreator(RestTemplate restTemplate) {
		this.requestFactory = restTemplate.getRequestFactory();
	}


	@Override
	public ClientHttpResponse createResponse(ClientHttpRequest request) throws IOException {
		Assert.state(request instanceof MockClientHttpRequest, "Expected mock request");
		MockClientHttpRequest mockRequest = (MockClientHttpRequest) request;
		ClientHttpRequest newRequest = this.requestFactory.createRequest(mockRequest.getURI(), mockRequest.getMethod());
		newRequest.getHeaders().putAll(mockRequest.getHeaders());
		StreamUtils.copy(mockRequest.getBodyAsBytes(), newRequest.getBody());
		return newRequest.execute();
	}
}

which is then used:

ResponseCreator executingResponseCreator = new ExecutingResponseCreator(restTemplate);
MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build();
...
server.expect(requestTo("/foo")).andRespond(withSuccess());
server.expect(requestTo("/bar")).andRespond(executingResponseCreator);

The rest of the code, MockRestServiceServer, ResponseActions, RequestExpectationManager implementations would remain unaware of any of this, which simplifies the implementation, and is generally easier to understand how it fits.

It would provide extra flexibility too because it becomes just another ResponseCreator that's no different from the rest. I'm thinking, we could provide an option for setting a default ResponseCreator in the MockRestServiceServer builder. That's independently useful, but if set to the ExecutingResponseCreator it would execute requests by default when andResponse isn't called. That's the effect that was sought in the original comment under #26381.

@rstoyanchev rstoyanchev added this to the Triage Queue milestone Jan 3, 2023
This commit adds a new convenience `ResponseCreator` implementation that
delegates to a `ClientHttpRequestFactory` to perform a request and
use the response.

For further convenience, a factory method based on a `RestTemplate` is
also added: `MockRestResponseCreators#byExecutingRequestUsing`. This
acts as a pseudo-DSL for fluently setting the ResponseCreator in a
`ResponseActions`.

The primary purpose of this implementation is to perform an actual
request to an external service and use the response in MockMVC.

Closes spring-projectsgh-26381
@simonbasle
Copy link
Contributor Author

@rstoyanchev I have reverted the previous implementation and introduced ExecutingResponseCreator instead per your suggestion.

@simonbasle
Copy link
Contributor Author

mmh I realize just now that the factory method in MockRestResponseCreators doesn't make much sense, because the ExecutingResponseCreator MUST be instantiated early on, before the RestTemplate's factory is changed...

I wonder how to improve the discoverability of the feature 🤔

Copy link
Contributor

@rstoyanchev rstoyanchev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks that looks very nice and simple.

For the visibility, we could:

  • add a paragraph in the Javadoc for MockRestResponseCreator that links to the alternative ExecutingResponseCreator along with an @see reference.
  • add something in the reference docs under this section.
  • yet another option is to add a sample test to the ones mentioned here, and that could use MockWebServer like in WebClientIntegrationTests for example

@simonbasle simonbasle changed the title Add MockRestServiceServer.andPerformRequest Add ExecutingResponseCreator to delegate request and response Jan 6, 2023
@rstoyanchev rstoyanchev modified the milestones: Triage Queue, 6.0.4 Jan 9, 2023
rstoyanchev added a commit that referenced this pull request Jan 9, 2023
mdeinum pushed a commit to mdeinum/spring-framework that referenced this pull request Jun 29, 2023
This commit adds a new `ResponseCreator` implementation that uses a
`ClientHttpRequestFactory` to perform an actual request.

Closes spring-projectsgh-29721
mdeinum pushed a commit to mdeinum/spring-framework that referenced this pull request Jun 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test Issues in the test module type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow MockRestServiceServer to validate requests but actually obtain response via HTTP call
2 participants