From 6dabd7c21207dff49df3a0bd2390a69a39972b14 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 28 Oct 2021 12:29:16 +0100 Subject: [PATCH] Update docs and samples on "slice" tests See gh-75 --- .../io/spring/sample/graphql/QueryTests.java | 9 +-- .../sample/graphql/SubscriptionTests.java | 9 +-- .../io/spring/sample/graphql/TestConfig.java | 37 ++++++++++++ .../src/docs/asciidoc/boot-starter.adoc | 60 +++++++++++-------- .../src/docs/asciidoc/testing.adoc | 16 ++--- 5 files changed, 86 insertions(+), 45 deletions(-) create mode 100644 samples/webflux-websocket/src/test/java/io/spring/sample/graphql/TestConfig.java diff --git a/samples/webflux-websocket/src/test/java/io/spring/sample/graphql/QueryTests.java b/samples/webflux-websocket/src/test/java/io/spring/sample/graphql/QueryTests.java index 946bd991..635cab60 100644 --- a/samples/webflux-websocket/src/test/java/io/spring/sample/graphql/QueryTests.java +++ b/samples/webflux-websocket/src/test/java/io/spring/sample/graphql/QueryTests.java @@ -20,8 +20,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.Import; import org.springframework.graphql.GraphQlService; import org.springframework.graphql.boot.test.GraphQlTest; import org.springframework.graphql.test.tester.GraphQlTester; @@ -29,10 +28,8 @@ import org.springframework.graphql.test.tester.GraphQlTester; /** * GraphQL query tests directly via {@link GraphQL}. */ -@GraphQlTest(controllers = SampleController.class, - includeFilters = @ComponentScan.Filter( - type = FilterType.ASSIGNABLE_TYPE, - classes = {ContextWebFilter.class, DataRepository.class})) +@GraphQlTest(SampleController.class) +@Import(TestConfig.class) public class QueryTests { private GraphQlTester graphQlTester; diff --git a/samples/webflux-websocket/src/test/java/io/spring/sample/graphql/SubscriptionTests.java b/samples/webflux-websocket/src/test/java/io/spring/sample/graphql/SubscriptionTests.java index 5321d660..86b0ac43 100644 --- a/samples/webflux-websocket/src/test/java/io/spring/sample/graphql/SubscriptionTests.java +++ b/samples/webflux-websocket/src/test/java/io/spring/sample/graphql/SubscriptionTests.java @@ -22,8 +22,7 @@ import reactor.core.publisher.Flux; import reactor.test.StepVerifier; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.Import; import org.springframework.graphql.GraphQlService; import org.springframework.graphql.boot.test.GraphQlTest; import org.springframework.graphql.test.tester.GraphQlTester; @@ -31,10 +30,8 @@ import org.springframework.graphql.test.tester.GraphQlTester; /** * GraphQL subscription tests directly via {@link GraphQL}. */ -@GraphQlTest(controllers = SampleController.class, - includeFilters = @ComponentScan.Filter( - type = FilterType.ASSIGNABLE_TYPE, - classes = {ContextWebFilter.class, DataRepository.class})) +@GraphQlTest(SampleController.class) +@Import(TestConfig.class) public class SubscriptionTests { private GraphQlTester graphQlTester; diff --git a/samples/webflux-websocket/src/test/java/io/spring/sample/graphql/TestConfig.java b/samples/webflux-websocket/src/test/java/io/spring/sample/graphql/TestConfig.java new file mode 100644 index 00000000..68eeafc2 --- /dev/null +++ b/samples/webflux-websocket/src/test/java/io/spring/sample/graphql/TestConfig.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.spring.sample.graphql; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Collaborator and additional components for {@link SampleController} slice tests. + */ +@Configuration +class TestConfig { + + @Bean + public ContextWebFilter contextWebFilter() { + return new ContextWebFilter(); + } + + @Bean + public DataRepository dataRepository() { + return new DataRepository(); + } + +} diff --git a/spring-graphql-docs/src/docs/asciidoc/boot-starter.adoc b/spring-graphql-docs/src/docs/asciidoc/boot-starter.adoc index 44df26ec..f79b12d0 100644 --- a/spring-graphql-docs/src/docs/asciidoc/boot-starter.adoc +++ b/spring-graphql-docs/src/docs/asciidoc/boot-starter.adoc @@ -440,25 +440,44 @@ repositories { The following sections cover a range of options for testing a Spring GraphQL application. [[boot-graphql-testing-graphqltest]] -=== Standalone GraphQL Server Tests +=== GraphQL Slice Tests -Use `@GraphQlTest` to test Spring GraphQL data `@Controller` and related GraphQL components -without involving a Web transport or a Web framework (Spring MVC or WebFlux). -`@GraphQlTest` auto-configures Spring GraphQL infrastructure and limits scanned beans to -`@Controller`, `RuntimeWiringConfigurer`, `JsonComponent`, `WebInterceptor`, `Converter`, -and `GenericConverter`, but excludes regular `@Component` and `@ConfigurationProperties` -beans. To include `@ConfigurationProperties` beans, use `@EnableConfigurationProperties`. +Use `@GraphQlTest` on a test class to create GraphQL tests focused on GraphQL request +execution, without involving a Web layer, and loading only a subset of the application +configuration. + +By default, `@GraphQlTest` limits scanning to the following beans: + +- `@Controller` +- `RuntimeWiringConfigurer` +- `JsonComponent` +- `Converter` +- `GenericConverter` + +Use the `controllers` attribute of `@GraphQlTest` to specify a controller class, or to +list all data controllers required to perform requests in a test class. Leaving it empty, +includes all controllers. + +To add collaborator and/or other components to a test class, use one of the following: + +- `@MockBean` fields in the test class. +- `@Import` an `@Configuration` class into the test class. +- Create a `@TestConfiguration` nested class. +- Broaden the component scan via `includeFilters` on `@GraphQlTest`. + +To add properties, use the `properties` attribute of `@GraphQlTest`, or add +`@EnableConfigurationProperties` on the test class. [NOTE] ==== -The arrangement is similar to the -{spring-boot-ref-docs}/features.html#features.testing.spring-boot-applications.spring-mvc-tests[@WevMvcTest support], -except there is no web framework in use, and `GraphQlService` is used to perform requests. +`@GraphQlTest` is comparable to +{spring-boot-ref-docs}/features.html#features.testing.spring-boot-applications.spring-mvc-tests[@WevMvcTest], +which also uses test "slices" to create focused Web controller tests. ==== [source,java,indent=0,subs="verbatim,quotes"] ---- -@GraphQlTest(controllers = BookController.class) +@GraphQlTest(BookController.class) public class BookControllerTests { @Autowired @@ -478,11 +497,11 @@ public class BookControllerTests { } ---- -This mode is useful to test subscriptions without a WebSocket transport. +This mode is useful to test subscriptions without WebSocket. [source,java,indent=0,subs="verbatim,quotes"] ---- -@GraphQlTest(controllers = GreetingController.class) +@GraphQlTest(GreetingController.class) public class GreetingControllerTests { @Autowired @@ -505,20 +524,9 @@ public class GreetingControllerTests { } ---- -`GraphQlService` is used to perform the above test. It represents common infrastructure -for HTTP and WebSocket transports that both Spring WebMvc and WebFlux handlers delegate to. -Therefore, it does not involve a web framework and does not apply the `WebInterceptor` -chain before and after the call to the GraphQL Java engine, which returns a Reactive -Streams `Publisher`. +`GraphQlService` performS the above request by calling directly the GraphQL Java engine, +which returns a Reactive Streams `Publisher`. -[NOTE] -.Testing multiple controllers with `@GraphQlTest` -==== -Because GraphQL is not about REST endpoints but navigating relations in an object graph, -multiple `@Controller` components can be involved in a single query. -For this case, the `@GraphQlTest` annotation supports testing multiple controllers through -its `controllers` attribute. -==== [[boot-graphql-testing-mock]] === Client and Mock Server Tests diff --git a/spring-graphql-docs/src/docs/asciidoc/testing.adoc b/spring-graphql-docs/src/docs/asciidoc/testing.adoc index e10b20d9..b359547e 100644 --- a/spring-graphql-docs/src/docs/asciidoc/testing.adoc +++ b/spring-graphql-docs/src/docs/asciidoc/testing.adoc @@ -1,9 +1,9 @@ [[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. +It's possible to test GraphQL requests with Spring's `WebTestClient`, just sending and +receiving JSON, but a number of GraphQL specific details make this approach more +cumbersome than is necessary. @@ -12,7 +12,6 @@ should be. `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. @@ -38,7 +37,10 @@ To create `GraphQlTester`, you only need a `GraphQlService`, and no transport: == `WebGraphQlTester` `WebGraphQlTester` extends `GraphQlTester` to add a workflow and configuration specific -to <>. You need one of the following inputs to create it: +to <>, and it always verifies GraphQL HTTP responses are 200 (OK). + + +To create `WebGraphQlTester`, you need one of the following inputs: - `WebTestClient` -- perform requests as an HTTP client, either against <> handlers without a server, or against a live server. @@ -61,7 +63,7 @@ For Spring WebFlux without a server, you can point to your Spring configuration: WebGraphQlTester tester = WebGraphQlTester.builder(client).build(); ---- -For Spring MVC without a server, use the `MockMvcWebTestClient` builder: +For Spring MVC without a server, the same but using `MockMvcWebTestClient`: [source,java,indent=0,subs="verbatim,quotes"] ---- @@ -76,7 +78,7 @@ For Spring MVC without a server, use the `MockMvcWebTestClient` builder: WebGraphQlTester tester = WebGraphQlTester.builder(client).build(); ---- -For tests against a live, running server: +To test against a live, running server: [source,java,indent=0,subs="verbatim,quotes"] ----