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.

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:

GraphQlSource graphQlSource = GraphQlSource.builder()
		.schemaResources(...)
		.runtimeWiringConfigurer(...)
		.build();

GraphQlService graphQlService = new ExecutionGraphQlService(graphQlSource);

GraphQlTester graphQlTester = GraphQlTester.builder(graphQlService).build();

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 Subscriptions.

For Spring WebFlux without a server, you can point to your Spring configuration:

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:

WebApplicationContext context = ... ;

WebTestClient client =
		MockMvcWebTestClient.bindToApplicationContext(context)
				.configureClient()
				.baseUrl("/graphql")
				.build();

WebGraphQlTester tester = WebGraphQlTester.builder(client).build();

For tests against a live, running server:

WebTestClient client =
		WebTestClient.bindToServer()
				.baseUrl("http://localhost:8080/graphql")
				.build();

WebGraphQlTester tester = WebGraphQlTester.builder(client).build();

Queries

Below is an example query test using JsonPath to extract all release versions in the GraphQL response.

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.

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:

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:

WebGraphQlTester graphQlTester = WebGraphQlTester.builder(client)
		.errorFilter(error -> ...)
		.build();

Or inspect all errors directly and that also marks them as filtered:

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:

graphQlTester.query(query).executeAndVerify();

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:

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:

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:

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.