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

Support of MockRestServiceServer for WebClient [SPR-15286] #19852

Closed
spring-projects-issues opened this issue Feb 24, 2017 · 22 comments
Closed
Labels
has: votes-jira Issues migrated from JIRA with more than 10 votes at the time of import in: test Issues in the test module in: web Issues in web modules (web, webmvc, webflux, websocket) status: declined A suggestion or change that we don't feel we should currently apply type: enhancement A general enhancement

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Feb 24, 2017

Stéphane Nicoll opened SPR-15286 and commented

Spring Boot has a @RestClientTest for pure client-side tests. We currently auto-configure MockRestServiceServer and bind any RestTemplate created by the RestTemplateBuilder to it.

This would be pretty awesome if we could port that feature to WebClient transparently if webflux is on the classpath. That would require that MockRestServiceServer can be configured with a WebClient in addition to a RestTemplate


Sub-tasks:

15 votes, 24 watchers

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

Indeed we'll most certainly need that. I'm putting it in the 5.1 backlog for now since I don't expect we'll manage that for 5.0.

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

In the mean time I suggest using the OkHttp MockWebServer (or similar) as do in our own WebClientIntegrationTests.

@spring-projects-issues
Copy link
Collaborator Author

Rob Worsnop commented

OkHttp was not a good substitute for us, so we created a temporary drop-in replacement for MockRestServiceServer. It, along with supporting classes, is here: https://github.com/vmware/connectors-workspace-one/tree/master/common/connectors-test/src/main/java/com/vmware/connectors/mock

Example usage here: https://github.com/vmware/connectors-workspace-one/blob/master/connectors/jira/src/test/java/com/vmware/connectors/jira/JiraControllerTests.java

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

What did you run into, i.e. where did using OkHttp fall short?

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Mar 12, 2018

Rob Worsnop commented

Our code does a parallel scatter-gather and aggregates the results. Because OkHttp is a "real" HTTP server, we get those results in a non-deterministic order, which makes it hard to match actual results to expected results.

I think I got around that by sorting the results with Flux.sort (in the production code, not tests) but then there was another problem: Our server returns JSON with hyperlinks pointing to the back-end it's accessing. With MockRestServiceServer, our code thinks it's talking to "http://bogus-host" and reliably formats links accordingly. With OkHttp, our server knows it's talking to "http://localhost:<random_port>", with the port changing with every test. Again, we can't easily match actual results to expected results.

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

Thanks for the feedback. Would JSONPath help in this scenario, i.e. dealing with data in non-deterministic order, and also parameterizing the host and port? On the flip side processing scatter gather in true random fashion probably makes for more realistic tests, which is desirable as long as it doesn't bring undue burden.

@spring-projects-issues
Copy link
Collaborator Author

Rob Worsnop commented

I thought I could probably work around all of the issues somehow, but at some point I realized that creating a WebClient-compatible mock was going to end up being easier.
Also, switching from AsyncRestTemplate to WebClient was a fairly major change, so being able to use virtually the same tests as before was pretty important. It gave us reassurance that behavior hadn't changed.

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

Good to know, thanks!

@spring-projects-issues
Copy link
Collaborator Author

Rob Worsnop commented

Quick update: I just used WebTestClient/OkHttp on a new project. It does seem much better than MockMvc/MockRestServiceServer.

One thing I noticed is that ordering in JSON arrays doesn't matter because I'm calling expectBody().json() on WebTestClient. Then I went back and noticed that we're calling content().string in the old code instead of content().json. (The reasons for doing this aren't entirely stupid, but they aren't that great either.)

Now I'm wondering if rewriting the old tests using WebTestClient/OkHttp might be the best way forward, now that the old tests have confirmed that moving to WebClient hasn't broken anything.

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

It would be useful to confirm if there are any specific issues in transitioning those tests. That is if you find the time the time for that exercise :)

@spring-projects-issues
Copy link
Collaborator Author

Craig Skinfill commented

any plans to implement this?  its making adopting WebFlux and WebClient harder since we can't test the same way we could with RestTemplate

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

Craig Skinfill, given the existence of the MockWebServer and others like WireMock, the idea is we might never build a MockRestServiceServer equivalent. I realize we have work to do to make this more clear in the docs, and to add some testing support for this in Spring Boot, but as far a direction, in the absence of any compelling reasons to build our own solution, MockWebServer (or similar mock server) is the present day alternative to MockRestServiceServer.

I have not done a complete analysis and comparison but it's clear that MockWebServer is in the same space and serves the same purpose, but is more widely applicable to any HTTP client, because it's exposed over HTTP through communication over a socket. So instead of using some sort of mock ClientHttpConnector with canned responses, you get to keep the HTTP client underneath (e.g. ReactorClientHttpConnector) and that leads to more complete testing. Over an actual socket it's more natural to simulate slow network conditions, chunked responses, and the like, and then in turn to test the impact with the actual HTTP client in charge of processing content on the wire. Even if we did create our own solution again, I'd consider strongly a similar approach but then again, why re-create what's available? Last but not least, it's worth mentioning also that MockWebServer has a large community which is important for maturity, learning resources, and feedback from diverse use cases.

 

 

@spring-projects-issues
Copy link
Collaborator Author

Craig Skinfill commented

Rossen Stoyanchev thanks for the explanation.  that makes sense to me.  Is there a preferred, from spring reactor perspective, mock server to consider?  Or any that have a closer integration with spring?

 

Thanks again.

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

Craig Skinfill we're using MockWebServer for our own tests, and it suits our needs so far. I don't have experience with others.

I think we probably need to think about Boot support for integration tests for code that uses the WebClient. Brian Clozel should we create a ticket for that in Boot to explore what such support could look like? Aside from that I don't see much need for Spring-specific configuration since client and server communicate over a socket, they're pretty decoupled.

@spring-projects-issues spring-projects-issues added in: test Issues in the test module type: enhancement A general enhancement has: votes-jira Issues migrated from JIRA with more than 10 votes at the time of import in: web Issues in web modules (web, webmvc, webflux, websocket) labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 5.x Backlog milestone Jan 11, 2019
@membersound
Copy link

Using WebClient for client-side requests is pretty useless if there is no proper mock in spring for testing our code. Having rewritten my RestTemplate client code to WebClient, I'm disappointed there is no replacement for MockRestServiceServer yet...

@dsundarraj2
Copy link

@membersound Have you used wiremock ?
WireMock can be used for mocking the responses for WebClient. Check this code repo which has examples for the same.
Repo:
https://github.com/code-with-dilip/learn-wiremock/tree/master/learn-wiremock-spring-cloud
TestCases:
https://github.com/code-with-dilip/learn-wiremock/blob/master/learn-wiremock-spring-cloud/src/test/java/com/learnwiremock/service/UserServiceWireMockRuleTest.java.
Cheers!

@membersound
Copy link

While this might work, I'd prefer relying on some kind of "official" framework, eg something that's included and maintained by spring themselves. Otherwise, if WebClient evolves by time, and WireMock is left behind, that might led to rewrites for all of my projects. As we all know, time is money, so that's too risky...

@rstoyanchev
Copy link
Contributor

@membersound I appreciate the point but there is also a lot of effort involved to create, maintain, and evolve something over time and it's hard to justify given the existing alternatives. HTTP provides loose coupling so implementations can exist and evolve independently. In this case we're even talking about mocking a server and shaping its behavior. I should think that switching from one to another shouldn't be as big a deal as it might seem at first. That said MockWebServer has more stars than the Spring Framework does and I don't think it is going to be a problem with longevity.

@SFBorland
Copy link

Is it listed somewhere in the official docs that MockWebServer is the recommended solution? I've spent a few days now looking for an official Spring version or trying to get existing stuff to work and finally stumbled on this thread..

@bclozel
Copy link
Member

bclozel commented Oct 3, 2019

@SFBorland We added a note about that in the reference documentation.

@SFBorland
Copy link

@bclozel I see it now...thanks.

@rstoyanchev rstoyanchev added the status: declined A suggestion or change that we don't feel we should currently apply label Nov 15, 2019
@rstoyanchev rstoyanchev removed this from the 5.x Backlog milestone Nov 15, 2019
@rstoyanchev
Copy link
Contributor

Closing as we have no further plans at this time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has: votes-jira Issues migrated from JIRA with more than 10 votes at the time of import in: test Issues in the test module in: web Issues in web modules (web, webmvc, webflux, websocket) status: declined A suggestion or change that we don't feel we should currently apply type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

6 participants