diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc index b160e51cfc7..ce0a737005b 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc @@ -444,7 +444,7 @@ There are `GraphQlTester` variants and Spring Boot will auto-configure them depe Spring Boot helps you to test your {spring-graphql-docs}#controllers[Spring GraphQL Controllers] with the `@GraphQlTest` annotation. `@GraphQlTest` auto-configures the Spring GraphQL infrastructure, without any transport nor server being involved. -This limits scanned beans to `@Controller`, `RuntimeWiringConfigurer`, `JsonComponent`, `Converter` and `GenericConverter`. +This limits scanned beans to `@Controller`, `RuntimeWiringConfigurer`, `JsonComponent`, `Converter`, `GenericConverter`, `DataFetcherExceptionResolver`, `Instrumentation` and `GraphQlSourceBuilderCustomizer`. Regular `@Component` and `@ConfigurationProperties` beans are not scanned when the `@GraphQlTest` annotation is used. `@EnableConfigurationProperties` can be used to include `@ConfigurationProperties` beans. diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTest.java index c096f037ba3..1a72744bdc8 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTest.java @@ -51,6 +51,9 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; *
  • {@code @JsonComponent} *
  • {@code Converter} *
  • {@code GenericConverter} + *
  • {@code DataFetcherExceptionResolver} + *
  • {@code Instrumentation} + *
  • {@code GraphQlSourceBuilderCustomizer} * *

    * The annotation does not automatically load {@code @Component}, {@code @Service}, @@ -121,7 +124,9 @@ public @interface GraphQlTest { * {@link SpringBootApplication @SpringBootApplication}. By default, only * {@code @Controller} (when no explicit {@link #controllers() controllers} are * defined), {@code RuntimeWiringConfigurer}, {@code @JsonComponent}, - * {@code Converter}, and {@code GenericConverter} beans are included. + * {@code Converter}, {@code GenericConverter}, {@code DataFetcherExceptionResolver}, + * {@code Instrumentation} and {@code GraphQlSourceBuilderCustomizer} beans are + * included. * @see #includeFilters() * @see #excludeFilters() * @return if default filters should be used diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTypeExcludeFilter.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTypeExcludeFilter.java index 1ae5b52f603..861650de745 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTypeExcludeFilter.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTypeExcludeFilter.java @@ -21,11 +21,15 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import graphql.execution.instrumentation.Instrumentation; + +import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer; import org.springframework.boot.context.TypeExcludeFilter; import org.springframework.boot.jackson.JsonComponent; import org.springframework.boot.test.autoconfigure.filter.StandardAnnotationCustomizableTypeExcludeFilter; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.GenericConverter; +import org.springframework.graphql.execution.DataFetcherExceptionResolver; import org.springframework.graphql.execution.RuntimeWiringConfigurer; import org.springframework.stereotype.Controller; import org.springframework.util.ClassUtils; @@ -51,6 +55,9 @@ public class GraphQlTypeExcludeFilter extends StandardAnnotationCustomizableType includes.add(RuntimeWiringConfigurer.class); includes.add(Converter.class); includes.add(GenericConverter.class); + includes.add(DataFetcherExceptionResolver.class); + includes.add(Instrumentation.class); + includes.add(GraphQlSourceBuilderCustomizer.class); for (String optionalInclude : OPTIONAL_INCLUDES) { try { includes.add(ClassUtils.forName(optionalInclude, null)); diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTypeExcludeFilterTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTypeExcludeFilterTests.java index 53fa09adcbd..098a3a765bb 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTypeExcludeFilterTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/graphql/GraphQlTypeExcludeFilterTests.java @@ -17,17 +17,35 @@ package org.springframework.boot.test.autoconfigure.graphql; import java.io.IOException; +import java.util.List; import com.fasterxml.jackson.databind.module.SimpleModule; +import graphql.ExecutionResult; +import graphql.GraphQLError; +import graphql.execution.instrumentation.ExecutionStrategyInstrumentationContext; +import graphql.execution.instrumentation.Instrumentation; +import graphql.execution.instrumentation.InstrumentationContext; +import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters; +import graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters; +import graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters; +import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters; +import graphql.execution.instrumentation.parameters.InstrumentationFieldParameters; +import graphql.execution.instrumentation.parameters.InstrumentationValidationParameters; +import graphql.language.Document; +import graphql.schema.DataFetchingEnvironment; import graphql.schema.idl.RuntimeWiring; +import graphql.validation.ValidationError; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; +import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.FilterType; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import org.springframework.graphql.execution.DataFetcherExceptionResolver; +import org.springframework.graphql.execution.GraphQlSource.Builder; import org.springframework.graphql.execution.RuntimeWiringConfigurer; import org.springframework.graphql.web.WebInput; import org.springframework.graphql.web.WebInterceptor; @@ -58,6 +76,9 @@ class GraphQlTypeExcludeFilterTests { assertThat(excludes(filter, ExampleRepository.class)).isTrue(); assertThat(excludes(filter, ExampleWebInterceptor.class)).isTrue(); assertThat(excludes(filter, ExampleModule.class)).isFalse(); + assertThat(excludes(filter, ExampleDataFetcherExceptionResolver.class)).isFalse(); + assertThat(excludes(filter, ExampleInstrumentation.class)).isFalse(); + assertThat(excludes(filter, ExampleGraphQlSourceBuilderCustomizer.class)).isFalse(); } @Test @@ -70,6 +91,9 @@ class GraphQlTypeExcludeFilterTests { assertThat(excludes(filter, ExampleRepository.class)).isTrue(); assertThat(excludes(filter, ExampleWebInterceptor.class)).isTrue(); assertThat(excludes(filter, ExampleModule.class)).isFalse(); + assertThat(excludes(filter, ExampleDataFetcherExceptionResolver.class)).isFalse(); + assertThat(excludes(filter, ExampleInstrumentation.class)).isFalse(); + assertThat(excludes(filter, ExampleGraphQlSourceBuilderCustomizer.class)).isFalse(); } @Test @@ -82,6 +106,9 @@ class GraphQlTypeExcludeFilterTests { assertThat(excludes(filter, ExampleRepository.class)).isTrue(); assertThat(excludes(filter, ExampleWebInterceptor.class)).isTrue(); assertThat(excludes(filter, ExampleModule.class)).isTrue(); + assertThat(excludes(filter, ExampleDataFetcherExceptionResolver.class)).isTrue(); + assertThat(excludes(filter, ExampleInstrumentation.class)).isTrue(); + assertThat(excludes(filter, ExampleGraphQlSourceBuilderCustomizer.class)).isTrue(); } @Test @@ -94,6 +121,9 @@ class GraphQlTypeExcludeFilterTests { assertThat(excludes(filter, ExampleRepository.class)).isFalse(); assertThat(excludes(filter, ExampleWebInterceptor.class)).isTrue(); assertThat(excludes(filter, ExampleModule.class)).isFalse(); + assertThat(excludes(filter, ExampleDataFetcherExceptionResolver.class)).isFalse(); + assertThat(excludes(filter, ExampleInstrumentation.class)).isFalse(); + assertThat(excludes(filter, ExampleGraphQlSourceBuilderCustomizer.class)).isFalse(); } @Test @@ -106,6 +136,9 @@ class GraphQlTypeExcludeFilterTests { assertThat(excludes(filter, ExampleRepository.class)).isTrue(); assertThat(excludes(filter, ExampleWebInterceptor.class)).isTrue(); assertThat(excludes(filter, ExampleModule.class)).isFalse(); + assertThat(excludes(filter, ExampleDataFetcherExceptionResolver.class)).isFalse(); + assertThat(excludes(filter, ExampleInstrumentation.class)).isFalse(); + assertThat(excludes(filter, ExampleGraphQlSourceBuilderCustomizer.class)).isFalse(); } private boolean excludes(GraphQlTypeExcludeFilter filter, Class type) throws IOException { @@ -181,4 +214,64 @@ class GraphQlTypeExcludeFilterTests { } + static class ExampleDataFetcherExceptionResolver implements DataFetcherExceptionResolver { + + @Override + public Mono> resolveException(Throwable exception, DataFetchingEnvironment environment) { + return null; + } + + } + + static class ExampleInstrumentation implements Instrumentation { + + @Override + public InstrumentationContext beginExecution(InstrumentationExecutionParameters parameters) { + return null; + } + + @Override + public InstrumentationContext beginParse(InstrumentationExecutionParameters parameters) { + return null; + } + + @Override + public InstrumentationContext> beginValidation( + InstrumentationValidationParameters parameters) { + return null; + } + + @Override + public InstrumentationContext beginExecuteOperation( + InstrumentationExecuteOperationParameters parameters) { + return null; + } + + @Override + public ExecutionStrategyInstrumentationContext beginExecutionStrategy( + InstrumentationExecutionStrategyParameters parameters) { + return null; + } + + @Override + public InstrumentationContext beginField(InstrumentationFieldParameters parameters) { + return null; + } + + @Override + public InstrumentationContext beginFieldFetch(InstrumentationFieldFetchParameters parameters) { + return null; + } + + } + + static class ExampleGraphQlSourceBuilderCustomizer implements GraphQlSourceBuilderCustomizer { + + @Override + public void customize(Builder builder) { + + } + + } + }