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

WebTestClient does not provide Hamcrest Matcher assertions for JSONPath [SPR-16729] #21270

Closed
spring-projects-issues opened this issue Apr 16, 2018 · 6 comments

Comments

@spring-projects-issues
Copy link
Collaborator

@spring-projects-issues spring-projects-issues commented Apr 16, 2018

Eric Deandrea opened SPR-16729 and commented

Seems that the reactive WebTestClient is missing some valuable assertions that are available on MockMvc.

With MockMvc I can do things like

this.mockMvc.perform(get("/some/url"))
  .andExpect(jsonPath("$.someNestedObject.*", Matchers.hasSize(5)))
  .andExpect(jsonPath("$.someNestedObject.anotherObject").value(Matchers.startsWith("Some String")));

The WebTestClient.jsonPath method doesn't have an overloaded

jsonPath(String expression, Matcher<T> matcher)

method like its MockMvcResultMatchers counterpart does. Also JsonPathAssertions doesn't have an overloaded

value(Matcher<T> matcher)

method like its JsonPathResultMatchers counterpart does. Under the covers both JsonPathResultMatchers & JsonPathAssertions utilize the exact same JsonPathExpectationsHelper which exposes the

public <T> void assertValue(String content, Matcher<T> matcher)

method which is needed.

Is there a particular reason this is missing or is it an oversight? Also seems that there is 0 support for assertions against XML using WebTestClient. Again, is there a specific reason as to why not?


Affects: 5.0.5

Issue Links:

  • #21278 Better support for testing JSON
  • #21282 Provide XML-based assertions in WebTestClient
  • #21116 Introduce consumeWith() methods in WebTestClient assertions

Referenced from: commits 20de500

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Apr 17, 2018

Eric Deandrea commented

I think this would solve the need:

In org.springframework.test.web.reactive.server.JsonPathAssertions:

/**
 * Applies {@link JsonPathExpectationsHelper#assertValue(String, Matcher)}
 */
public <T> WebTestClient.BodyContentSpec matches(Matcher<T> matcher) {
	this.pathHelper.assertValue(this.content, matcher);
	return this.bodySpec;
}

In org.springframework.test.web.reactive.server.samples:

@Test
public void jsonPathMatches() {
	this.client.get().uri("/persons")
			.accept(MediaType.APPLICATION_JSON_UTF8)
			.exchange()
			.expectStatus().isOk()
			.expectBody()
			.jsonPath("$[*]").matches(Matchers.hasSize(3))
			.jsonPath("$[0].name").matches(Matchers.is("Jane"))
			.jsonPath("$[1].name").matches(Matchers.is("Jason"))
			.jsonPath("$[2].name").matches(Matchers.is("John"));
	}

Loading

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Apr 17, 2018

Eric Deandrea commented

I submitted #1794 for this.

Loading

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Apr 19, 2018

Rossen Stoyanchev commented

Unlike MockMvc, the WebTestClient does not have expose Hamcrest by choice. There are lots of ways and libraries to assert with. For example Spring Boot favors the more fluent AssertJ style. The idea is to try and provide a core set of built-in options, but otherwise get out of the way and expose the underlying data via java.util.function.Consumer callbacks, so that can be used with any assertion library.

One option would be to expose Consumer-based methods for the values from a JSONPath on JsonPathAssertions, e.g.stringValue(Consumer<String>), booleanValue(Consumer<Boolean>), arrayValue(Consumer<List<?>> consumer), etc. However since many JSON paths may be evaluated, this could be too repetitive.

A probably better option would be to update the underlying JsonPathAssertionsHelper to expose a more fluent API, so it can be used directly, e.g. via Consumer method for the whole body, like this:

this.client.get().uri("/persons")
        .accept(MediaType.APPLICATION_JSON_UTF8)
        .exchange()
        .expectStatus().isOk()
        .expectBody()
        .consumeWith(result -> {
            // use fluent API based on JsonPathExpectationsHelper here..
        });

In addition to that, we could add a few more built-in methods on JSONPath assertions to make it more useful.

Loading

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Apr 19, 2018

Eric Deandrea commented

Whatever we do here we also need to support XPath-based assertions, so just exposing the JsonPathExpectationsHelper isn't enough....

See #21282

Loading

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Apr 20, 2018

Rossen Stoyanchev commented

Yes the two are related. I just didn't get a chance to comment there yet.

Loading

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Apr 20, 2018

Rossen Stoyanchev commented

Related discussion for AssertJ-style assertions in #21278.

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants