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

MockRestServiceServerAutoConfiguration with RestTemplate and RestClient together throws incorrect exception #38820

Closed
michaldo opened this issue Dec 14, 2023 · 4 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@michaldo
Copy link
Contributor

michaldo commented Dec 14, 2023

It should be possible to have together RestTemplate and RestClient in application and test them independently.

Unfortunately, currently if RestTemplate is used, RestClient cannot be tested:

org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerAutoConfiguration.DeferredRequestExpectationManager#getDelegate

if (!restTemplateExpectationManagers.isEmpty()) {
    Assert.state(restTemplateExpectationManagers.size() == 1,
            "Unable to use auto-configured MockRestServiceServer since "
                    + "MockServerRestTemplateCustomizer has been bound to more than one RestTemplate");
    return restTemplateExpectationManagers.values().iterator().next();
}
Assert.state(restClientExpectationManagers.size() == 1,
        "Unable to use auto-configured MockRestServiceServer since "
                + "MockServerRestClientCustomizer has been bound to more than one RestClient");
return restClientExpectationManagers.values().iterator().next();
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Dec 14, 2023
@philwebb
Copy link
Member

I'm not sure I understand your setup. Could you please provide a minimal sample project (either a GitHub project or zip file) that shows what you are trying to do.

@philwebb philwebb added the status: waiting-for-feedback We need additional information before we can continue label Dec 15, 2023
@michaldo
Copy link
Contributor Author

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Dec 15, 2023
@mhalbritter mhalbritter added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged status: feedback-provided Feedback has been provided labels Jan 9, 2024
@mhalbritter
Copy link
Contributor

mhalbritter commented Jan 9, 2024

The problem is in org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerAutoConfiguration.DeferredRequestExpectationManager#getDelegate:

When a RestTemplate is in the context, restTemplateExpectationManagers contains 1 entry, which is then always used. The expectation manager, which may be in restClientExpectationManagers is then ignored.

I suspect that the RestClient case then uses the wrong expectation manager when the mocked response is returned.

That's the error I'm getting:

java.lang.AssertionError: No further requests expected: HTTP GET /
0 request(s) executed.


	at org.springframework.test.web.client.AbstractRequestExpectationManager.createUnexpectedRequestError(AbstractRequestExpectationManager.java:193)
	at org.springframework.test.web.client.SimpleRequestExpectationManager.matchRequest(SimpleRequestExpectationManager.java:59)
	at org.springframework.test.web.client.AbstractRequestExpectationManager.validateRequest(AbstractRequestExpectationManager.java:91)
	at org.springframework.test.web.client.MockRestServiceServer$MockClientHttpRequestFactory$1.executeInternal(MockRestServiceServer.java:324)
	at org.springframework.mock.http.client.MockClientHttpRequest.execute(MockClientHttpRequest.java:126)
	at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchangeInternal(DefaultRestClient.java:453)
	at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.retrieve(DefaultRestClient.java:424)
	at com.example.restclientjson.RestClientAndTemplateTogetherTest.test(RestClientAndTemplateTogetherTest.java:42)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

@mhalbritter mhalbritter added this to the 3.2.x milestone Jan 9, 2024
@scottfrederick scottfrederick self-assigned this Jan 10, 2024
@scottfrederick
Copy link
Contributor

If you have two RestTemplate beans or two RestClient beans in your application, you can't use an auto-wired MockRestServiceServer in your test. If you do, you will get an exception with a message like Unable to use auto-configured MockRestServiceServer since MockServerRestTemplateCustomizer has been bound to more than one RestTemplate when you try to set an expectation. This is mentioned in the JavaDoc for AutoConfigureMockRestServiceServer.java but the language is not completely clear:

If multiple RestTemplates or RestClients are in use, inject a MockServerRestTemplateCustomizer and use getServer(RestTemplate), or inject a MockServerRestClientCustomizer and use getServer(RestClient.Builder), or bind a MockRestServiceServer directly.

The same is true when you have one RestTemplate and one RestClient, but this condition is not currently detected in the code like it should be so that an exception with a descriptive message can be thrown. We'll fix that.

Applying the suggestion from the JavaDoc to the provided sample would look like this:

    @Test
    void test(@Autowired RestClient restClient, @Autowired MockServerRestClientCustomizer customizer) {

        // given
        customizer.getServer().expect(requestTo("/")).andRespond(withSuccess());

        // when then
        restClient.get()
                .uri("/")
                .retrieve();
    }

@scottfrederick scottfrederick modified the milestones: 3.2.x, 3.2.2 Jan 17, 2024
@scottfrederick scottfrederick changed the title MockRestServiceServerAutoConfiguration does not support RestTemplate and RestClient together MockRestServiceServerAutoConfiguration with RestTemplate and RestClient together throws incorrect exception Jan 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

5 participants