Polishing and minor refactoring in reference docs

This commit is contained in:
Rossen Stoyanchev
2021-08-09 14:21:33 +01:00
parent 3567a062ab
commit a78abb7dc8
2 changed files with 223 additions and 222 deletions

View File

@@ -159,7 +159,7 @@ see <<boot-graphql-web>> for details, or check `GraphQlWebMvcAutoConfiguration`
[[execution]]
== Query Execution
== Request Execution
`GraphQlService` is the main Spring GraphQL abstraction to call GraphQL Java to execute
requests. Underlying transports, such as the <<web-transports>>, delegate to `GraphQlService` to
@@ -367,7 +367,7 @@ Such repositories are auto-detected in the <<boot-repositories-querydsl,Boot sta
[[data-security]]
[[security]]
== Security
The path to a <<web-transports, Web>> GraphQL endpoint can be secured with HTTP
@@ -387,226 +387,7 @@ The Spring GraphQL repository contains samples for
[[testing]]
== Testing
You can test GraphQL requests using Spring's `WebTestClient`, just send and receive
JSON, but a number of GraphQL specific details make this approach more cumbersome than it
should be.
[[testing-graphqltester]]
=== `GraphQlTester`
`GraphQlTester` defines a workflow to test GraphQL requests with the following benefits:
- Verify GraphQL responses are 200 (OK).
- Verify no unexpected errors under the "errors" key in the response.
- Decode under the "data" key in the response.
- Use JsonPath to decode different parts of the response.
- Test subscriptions.
To create `GraphQlTester`, you only need a `GraphQlService`, and no transport:
[source,java,indent=0,subs="verbatim,quotes"]
----
GraphQlSource graphQlSource = GraphQlSource.builder()
.schemaResources(...)
.runtimeWiring(...)
.build();
GraphQlService graphQlService = new ExecutionGraphQlService(graphQlSource);
GraphQlTester graphQlTester = GraphQlTester.builder(graphQlService).build();
----
[[testing-webgraphqltester]]
=== `WebGraphQlTester`
`WebGraphQlTester` extends `GraphQlTester` to add a workflow and configuration specific
to <<web-transports>>. You need one of the following inputs to create it:
- `WebTestClient` -- perform requests as an HTTP client, either against <<web-http>>
handlers without a server, or against a live server.
- `WebGraphQlHandler` -- perform requests through the <<web-interception>> chain used
by both <<web-http>> and <<web-websocket>> handlers, which in effect is testing without
a Web framework. One reason to use this is for <<testing-subscriptions>>.
For Spring WebFlux without a server, you can point to your Spring configuration:
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext context = ... ;
WebTestClient client =
WebTestClient.bindToApplicationContext(context)
.configureClient()
.baseUrl("/graphql")
.build();
WebGraphQlTester tester = WebGraphQlTester.builder(client).build();
----
For Spring MVC without a server, use the `MockMvcWebTestClient` builder:
[source,java,indent=0,subs="verbatim,quotes"]
----
WebApplicationContext context = ... ;
WebTestClient client =
MockMvcWebTestClient.bindToApplicationContext(context)
.configureClient()
.baseUrl("/graphql")
.build();
WebGraphQlTester tester = WebGraphQlTester.builder(client).build();
----
For tests against a live, running server:
[source,java,indent=0,subs="verbatim,quotes"]
----
WebTestClient client =
WebTestClient.bindToServer()
.baseUrl("http://localhost:8080/graphql")
.build();
WebGraphQlTester tester = WebGraphQlTester.builder(client).build();
----
[[testing-queries]]
=== Queries
Below is an example query test using
https://github.com/json-path/JsonPath[JsonPath] to extract all release versions in the
GraphQL response.
[source,java,indent=0,subs="verbatim,quotes"]
----
String query = "{" +
" project(slug:\"spring-framework\") {" +
" releases {" +
" version" +
" }"+
" }" +
"}";
graphQlTester.query(query)
.execute()
.path("project.releases[*].version")
.entityList(String.class)
.hasSizeGreaterThan(1);
----
The JsonPath is relative to the "data" section of the response.
[[testing-errors]]
=== Errors
Tests cannot use verify data, if there are errors under the "errors" key in the response
has errors. If necessary to ignore an error, use an error filter `Predicate`:
[source,java,indent=0,subs="verbatim,quotes"]
----
graphQlTester.query(query)
.execute()
.errors()
.filter(error -> ...)
.verify()
.path("project.releases[*].version")
.entityList(String.class)
.hasSizeGreaterThan(1);
----
An error filter can be registered globally and apply to all tests:
[source,java,indent=0,subs="verbatim,quotes"]
----
WebGraphQlTester graphQlTester = WebGraphQlTester.builder(client)
.errorFilter(error -> ...)
.build();
----
Or inspect all errors directly and that also marks them as filtered:
[source,java,indent=0,subs="verbatim,quotes"]
----
graphQlTester.query(query)
.execute()
.errors()
.satisfy(errors -> {
// ...
});
----
If a request does not have any response data (e.g. mutation), use `executeAndVerify`
instead of `execute` to verify there are no errors in the response:
[source,java,indent=0,subs="verbatim,quotes"]
----
graphQlTester.query(query).executeAndVerify();
----
[[testing-subscriptions]]
=== Subscriptions
The `executeSubscription` method defines a workflow specific to subscriptions which return
a stream of responses instead of a single response.
To test subscriptions, you can create `GraphQlTester` with a `GraphQlService`, which
calls `graphql.GraphQL` directly and that returns a stream of responses:
[source,java,indent=0,subs="verbatim,quotes"]
----
GraphQlService service = ... ;
GraphQlTester graphQlTester = GraphQlTester.builder(service).build();
Flux<String> result = graphQlTester.query("subscription { greetings }")
.executeSubscription()
.toFlux("greetings", String.class); // decode each response
----
The `StepVerifier` from Project Reactor is useful to verify a stream:
[source,java,indent=0,subs="verbatim,quotes"]
----
Flux<String> result = graphQlTester.query("subscription { greetings }")
.executeSubscription()
.toFlux("greetings", String.class);
StepVerifier.create(result)
.expectNext("Hi")
.expectNext("Bonjour")
.expectNext("Hola")
.verifyComplete();
----
To test with the <<web-interception>> chain, you can create `WebGraphQlTester` with a
`WebGraphQlHandler`:
[source,java,indent=0,subs="verbatim,quotes"]
----
GraphQlService service = ... ;
WebGraphQlHandler handler = WebGraphQlHandler.builder(service)
.interceptor((input, next) -> next.handle(input))
.build();
WebGraphQlTester graphQlTester = WebGraphQlTester.builder(handler).build();
----
Currently, Spring GraphQL does not support testing with a WebSocket client, and it
cannot be used for integration test of GraphQL over WebSocket requests.
include::testing.adoc[leveloffset=+1]

View File

@@ -0,0 +1,220 @@
[[testing]]
= Testing
You can test GraphQL requests using Spring's `WebTestClient`, just send and receive
JSON, but a number of GraphQL specific details make this approach more cumbersome than it
should be.
[[testing-graphqltester]]
== `GraphQlTester`
`GraphQlTester` defines a workflow to test GraphQL requests with the following benefits:
- Verify GraphQL responses are 200 (OK).
- Verify no unexpected errors under the "errors" key in the response.
- Decode under the "data" key in the response.
- Use JsonPath to decode different parts of the response.
- Test subscriptions.
To create `GraphQlTester`, you only need a `GraphQlService`, and no transport:
[source,java,indent=0,subs="verbatim,quotes"]
----
GraphQlSource graphQlSource = GraphQlSource.builder()
.schemaResources(...)
.runtimeWiringConfigurer(...)
.build();
GraphQlService graphQlService = new ExecutionGraphQlService(graphQlSource);
GraphQlTester graphQlTester = GraphQlTester.builder(graphQlService).build();
----
[[testing-webgraphqltester]]
== `WebGraphQlTester`
`WebGraphQlTester` extends `GraphQlTester` to add a workflow and configuration specific
to <<web-transports>>. You need one of the following inputs to create it:
- `WebTestClient` -- perform requests as an HTTP client, either against <<web-http>>
handlers without a server, or against a live server.
- `WebGraphQlHandler` -- perform requests through the <<web-interception>> chain used
by both <<web-http>> and <<web-websocket>> handlers, which in effect is testing without
a Web framework. One reason to use this is for <<testing-subscriptions>>.
For Spring WebFlux without a server, you can point to your Spring configuration:
[source,java,indent=0,subs="verbatim,quotes"]
----
ApplicationContext context = ... ;
WebTestClient client =
WebTestClient.bindToApplicationContext(context)
.configureClient()
.baseUrl("/graphql")
.build();
WebGraphQlTester tester = WebGraphQlTester.builder(client).build();
----
For Spring MVC without a server, use the `MockMvcWebTestClient` builder:
[source,java,indent=0,subs="verbatim,quotes"]
----
WebApplicationContext context = ... ;
WebTestClient client =
MockMvcWebTestClient.bindToApplicationContext(context)
.configureClient()
.baseUrl("/graphql")
.build();
WebGraphQlTester tester = WebGraphQlTester.builder(client).build();
----
For tests against a live, running server:
[source,java,indent=0,subs="verbatim,quotes"]
----
WebTestClient client =
WebTestClient.bindToServer()
.baseUrl("http://localhost:8080/graphql")
.build();
WebGraphQlTester tester = WebGraphQlTester.builder(client).build();
----
[[testing-queries]]
== Queries
Below is an example query test using
https://github.com/json-path/JsonPath[JsonPath] to extract all release versions in the
GraphQL response.
[source,java,indent=0,subs="verbatim,quotes"]
----
String query = "{" +
" project(slug:\"spring-framework\") {" +
" releases {" +
" version" +
" }"+
" }" +
"}";
graphQlTester.query(query)
.execute()
.path("project.releases[*].version")
.entityList(String.class)
.hasSizeGreaterThan(1);
----
The JsonPath is relative to the "data" section of the response.
[[testing-errors]]
== Errors
Tests cannot use verify data, if there are errors under the "errors" key in the response
has errors. If necessary to ignore an error, use an error filter `Predicate`:
[source,java,indent=0,subs="verbatim,quotes"]
----
graphQlTester.query(query)
.execute()
.errors()
.filter(error -> ...)
.verify()
.path("project.releases[*].version")
.entityList(String.class)
.hasSizeGreaterThan(1);
----
An error filter can be registered globally and apply to all tests:
[source,java,indent=0,subs="verbatim,quotes"]
----
WebGraphQlTester graphQlTester = WebGraphQlTester.builder(client)
.errorFilter(error -> ...)
.build();
----
Or inspect all errors directly and that also marks them as filtered:
[source,java,indent=0,subs="verbatim,quotes"]
----
graphQlTester.query(query)
.execute()
.errors()
.satisfy(errors -> {
// ...
});
----
If a request does not have any response data (e.g. mutation), use `executeAndVerify`
instead of `execute` to verify there are no errors in the response:
[source,java,indent=0,subs="verbatim,quotes"]
----
graphQlTester.query(query).executeAndVerify();
----
[[testing-subscriptions]]
== Subscriptions
The `executeSubscription` method defines a workflow specific to subscriptions which return
a stream of responses instead of a single response.
To test subscriptions, you can create `GraphQlTester` with a `GraphQlService`, which
calls `graphql.GraphQL` directly and that returns a stream of responses:
[source,java,indent=0,subs="verbatim,quotes"]
----
GraphQlService service = ... ;
GraphQlTester graphQlTester = GraphQlTester.builder(service).build();
Flux<String> result = graphQlTester.query("subscription { greetings }")
.executeSubscription()
.toFlux("greetings", String.class); // decode each response
----
The `StepVerifier` from Project Reactor is useful to verify a stream:
[source,java,indent=0,subs="verbatim,quotes"]
----
Flux<String> result = graphQlTester.query("subscription { greetings }")
.executeSubscription()
.toFlux("greetings", String.class);
StepVerifier.create(result)
.expectNext("Hi")
.expectNext("Bonjour")
.expectNext("Hola")
.verifyComplete();
----
To test with the <<web-interception>> chain, you can create `WebGraphQlTester` with a
`WebGraphQlHandler`:
[source,java,indent=0,subs="verbatim,quotes"]
----
GraphQlService service = ... ;
WebGraphQlHandler handler = WebGraphQlHandler.builder(service)
.interceptor((input, next) -> next.handle(input))
.build();
WebGraphQlTester graphQlTester = WebGraphQlTester.builder(handler).build();
----
Currently, Spring GraphQL does not support testing with a WebSocket client, and it
cannot be used for integration test of GraphQL over WebSocket requests.