Add GraphQlTest annotation
Prior to this commit, we could only test Spring GraphQL applications with a complete application - all application and infrastructure components were involved. While using `@SpringBootTest` is often useful for complete integration tests (with or without a live running server), we often want to write lean integration tests and test slices of our application. Just like `@WebMvcTest` or `@WebFluxTest`, this commit introduces the support for `@GraphQlTest`. This annotation helps us to test a particular slice of our application: a hand-picked selection of `@Controller`, plus `RuntimeWiringConfigurer` and `WebInterceptor` beans. Other `@Component` must be imported or mocked for those tests. This commit also refactors the existing auto-configuration to enable this use case. The `WebGraphQlHandlerAutoConfiguration` now holds the required components for `@GraphQlTest`, while other web-related auto-configurations bring the web framework and transport infrastructures. Closes gh-75
This commit is contained in:
@@ -48,6 +48,7 @@ dependencies {
|
||||
compileOnly project(':spring-graphql-test')
|
||||
compileOnly 'org.junit.jupiter:junit-jupiter-api'
|
||||
compileOnly 'org.springframework.boot:spring-boot-test'
|
||||
compileOnly 'org.springframework.boot:spring-boot-test-autoconfigure'
|
||||
|
||||
compileOnly 'com.google.code.findbugs:jsr305'
|
||||
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
|
||||
|
||||
@@ -17,14 +17,11 @@
|
||||
package org.springframework.graphql.boot;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import graphql.GraphQL;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
@@ -37,12 +34,8 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.format.support.FormattingConversionService;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
import org.springframework.graphql.web.WebInterceptor;
|
||||
import org.springframework.graphql.web.webflux.GraphQlHttpHandler;
|
||||
import org.springframework.graphql.web.webflux.GraphQlWebSocketHandler;
|
||||
import org.springframework.graphql.web.webflux.GraphiQlHandler;
|
||||
@@ -75,27 +68,12 @@ import static org.springframework.web.reactive.function.server.RequestPredicates
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||
@ConditionalOnClass({GraphQL.class, GraphQlHttpHandler.class})
|
||||
@ConditionalOnBean(GraphQlSource.class)
|
||||
@AutoConfigureAfter(GraphQlServiceAutoConfiguration.class)
|
||||
@AutoConfigureAfter(WebGraphQlHandlerAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(GraphQlCorsProperties.class)
|
||||
public class GraphQlWebFluxAutoConfiguration {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(GraphQlWebFluxAutoConfiguration.class);
|
||||
|
||||
@Bean
|
||||
public AnnotatedControllerConfigurer annotatedControllerConfigurer(@Qualifier("webFluxConversionService") FormattingConversionService conversionService) {
|
||||
AnnotatedControllerConfigurer annotatedControllerConfigurer = new AnnotatedControllerConfigurer();
|
||||
annotatedControllerConfigurer.setConversionService(conversionService);
|
||||
return annotatedControllerConfigurer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(GraphQlService.class)
|
||||
@ConditionalOnMissingBean
|
||||
public WebGraphQlHandler webGraphQlHandler(GraphQlService service, ObjectProvider<WebInterceptor> interceptors) {
|
||||
return WebGraphQlHandler.builder(service)
|
||||
.interceptors(interceptors.orderedStream().collect(Collectors.toList())).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler) {
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.graphql.boot;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.websocket.server.ServerContainer;
|
||||
|
||||
@@ -26,8 +25,6 @@ import graphql.GraphQL;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
@@ -41,13 +38,8 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.format.support.FormattingConversionService;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.graphql.execution.ThreadLocalAccessor;
|
||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
import org.springframework.graphql.web.WebInterceptor;
|
||||
import org.springframework.graphql.web.webmvc.GraphQlHttpHandler;
|
||||
import org.springframework.graphql.web.webmvc.GraphQlWebSocketHandler;
|
||||
import org.springframework.graphql.web.webmvc.GraphiQlHandler;
|
||||
@@ -82,29 +74,12 @@ import static org.springframework.web.servlet.function.RequestPredicates.content
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@ConditionalOnClass({GraphQL.class, GraphQlHttpHandler.class})
|
||||
@ConditionalOnBean(GraphQlSource.class)
|
||||
@AutoConfigureAfter(GraphQlServiceAutoConfiguration.class)
|
||||
@AutoConfigureAfter(WebGraphQlHandlerAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(GraphQlCorsProperties.class)
|
||||
public class GraphQlWebMvcAutoConfiguration {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(GraphQlWebMvcAutoConfiguration.class);
|
||||
|
||||
@Bean
|
||||
public AnnotatedControllerConfigurer annotatedControllerConfigurer(@Qualifier("mvcConversionService") FormattingConversionService conversionService) {
|
||||
AnnotatedControllerConfigurer annotatedControllerConfigurer = new AnnotatedControllerConfigurer();
|
||||
annotatedControllerConfigurer.setConversionService(conversionService);
|
||||
return annotatedControllerConfigurer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(GraphQlService.class)
|
||||
@ConditionalOnMissingBean
|
||||
public WebGraphQlHandler webGraphQlHandler(GraphQlService service, ObjectProvider<WebInterceptor> interceptorsProvider,
|
||||
ObjectProvider<ThreadLocalAccessor> accessorsProvider) {
|
||||
return WebGraphQlHandler.builder(service)
|
||||
.interceptors(interceptorsProvider.orderedStream().collect(Collectors.toList()))
|
||||
.threadLocalAccessors(accessorsProvider.orderedStream().collect(Collectors.toList())).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler) {
|
||||
|
||||
@@ -16,23 +16,31 @@
|
||||
|
||||
package org.springframework.graphql.boot;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import graphql.GraphQL;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;
|
||||
import org.springframework.graphql.execution.BatchLoaderRegistry;
|
||||
import org.springframework.graphql.execution.DefaultBatchLoaderRegistry;
|
||||
import org.springframework.graphql.execution.ExecutionGraphQlService;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.graphql.execution.ThreadLocalAccessor;
|
||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
import org.springframework.graphql.web.WebInterceptor;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for creating a
|
||||
* {@link GraphQlService}.
|
||||
* {@link WebGraphQlHandler}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 1.0.0
|
||||
@@ -41,11 +49,12 @@ import org.springframework.graphql.execution.GraphQlSource;
|
||||
@ConditionalOnClass({GraphQL.class, GraphQlService.class})
|
||||
@ConditionalOnMissingBean(GraphQlService.class)
|
||||
@AutoConfigureAfter(GraphQlAutoConfiguration.class)
|
||||
public class GraphQlServiceAutoConfiguration {
|
||||
public class WebGraphQlHandlerAutoConfiguration {
|
||||
|
||||
private final BatchLoaderRegistry batchLoaderRegistry = new DefaultBatchLoaderRegistry();
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public BatchLoaderRegistry batchLoaderRegistry() {
|
||||
return this.batchLoaderRegistry;
|
||||
}
|
||||
@@ -58,4 +67,21 @@ public class GraphQlServiceAutoConfiguration {
|
||||
return service;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public AnnotatedControllerConfigurer annotatedControllerConfigurer() {
|
||||
AnnotatedControllerConfigurer annotatedControllerConfigurer = new AnnotatedControllerConfigurer();
|
||||
annotatedControllerConfigurer.setConversionService(new DefaultFormattingConversionService());
|
||||
return annotatedControllerConfigurer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public WebGraphQlHandler webGraphQlHandler(GraphQlService service, ObjectProvider<WebInterceptor> interceptorsProvider,
|
||||
ObjectProvider<ThreadLocalAccessor> accessorsProvider) {
|
||||
return WebGraphQlHandler.builder(service)
|
||||
.interceptors(interceptorsProvider.orderedStream().collect(Collectors.toList()))
|
||||
.threadLocalAccessors(accessorsProvider.orderedStream().collect(Collectors.toList())).build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2020-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 org.springframework.graphql.boot.test;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
|
||||
/**
|
||||
* {@link ImportAutoConfiguration Auto-configuration imports} for typical Spring GraphQL
|
||||
* tests. Most tests should consider using {@link GraphQlTest @GraphQlTest} rather than
|
||||
* using this annotation directly.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 1.0.0
|
||||
* @see GraphQlTest
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@ImportAutoConfiguration
|
||||
public @interface AutoConfigureGraphQl {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2020-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 org.springframework.graphql.boot.test;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;
|
||||
import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache;
|
||||
import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters;
|
||||
import org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.graphql.boot.test.tester.AutoConfigureWebGraphQlTester;
|
||||
import org.springframework.test.context.BootstrapWith;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
/**
|
||||
* Annotation that can be used for a Spring GraphQL test that focuses
|
||||
* <strong>only</strong> on Spring GraphQL components, without involving web frameworks.
|
||||
* <p>
|
||||
* Using this annotation will disable full auto-configuration and instead apply only
|
||||
* configuration relevant to GraphQL tests (i.e. {@code @Controller},
|
||||
* {@code @JsonComponent}, {@code Converter}/{@code GenericConverter},
|
||||
* {@code WebInterceptor} and {@code RuntimeWiringConfigurer} beans but not
|
||||
* {@code @Component}, {@code @Service} or {@code @Repository} beans).
|
||||
* <p>
|
||||
* By default, tests annotated with {@code @GraphQlTest} will also auto-configure a
|
||||
* {@link org.springframework.graphql.test.tester.WebGraphQlTester}. For more fine-grained control of GraphQlTester the
|
||||
* {@link AutoConfigureWebGraphQlTester @AutoConfigureGraphQlTester} annotation can be used.
|
||||
* <p>
|
||||
* Typically {@code @GraphQlTest} is used in combination with
|
||||
* {@link org.springframework.boot.test.mock.mockito.MockBean @MockBean} or
|
||||
* {@link org.springframework.context.annotation.Import @Import} to create any collaborators required by your
|
||||
* {@code @Controller} beans.
|
||||
* <p>
|
||||
* If you are looking to load your full application configuration and use {@code WebGraphQlTester},
|
||||
* you should consider {@link org.springframework.boot.test.context.SpringBootTest @SpringBootTest} combined with
|
||||
* {@link AutoConfigureWebGraphQlTester @AutoConfigureWebGraphQlTester} rather than this
|
||||
* annotation.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 1.0.0
|
||||
* @see AutoConfigureWebGraphQlTester
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@BootstrapWith(GraphQlTestContextBootstrapper.class)
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@OverrideAutoConfiguration(enabled = false)
|
||||
@TypeExcludeFilters(GraphQlTypeExcludeFilter.class)
|
||||
@AutoConfigureCache
|
||||
@AutoConfigureJson
|
||||
@AutoConfigureGraphQl
|
||||
@AutoConfigureWebGraphQlTester
|
||||
@ImportAutoConfiguration
|
||||
public @interface GraphQlTest {
|
||||
|
||||
/**
|
||||
* Properties in form {@literal key=value} that should be added to the Spring
|
||||
* {@link Environment} before the test runs.
|
||||
* @return the properties to add
|
||||
*/
|
||||
String[] properties() default {};
|
||||
|
||||
/**
|
||||
* Specifies the controllers to test. This is an alias of {@link #controllers()} which
|
||||
* can be used for brevity if no other attributes are defined. See
|
||||
* {@link #controllers()} for details.
|
||||
* @see #controllers()
|
||||
* @return the controllers to test
|
||||
*/
|
||||
@AliasFor("controllers")
|
||||
Class<?>[] value() default {};
|
||||
|
||||
/**
|
||||
* Specifies the controllers to test. May be left blank if all {@code @Controller}
|
||||
* beans should be added to the application context.
|
||||
* @see #value()
|
||||
* @return the controllers to test
|
||||
*/
|
||||
@AliasFor("value")
|
||||
Class<?>[] controllers() default {};
|
||||
|
||||
/**
|
||||
* Determines if default filtering should be used with
|
||||
* {@link SpringBootApplication @SpringBootApplication}. By default, only
|
||||
* {@code @Controller} (when no explicit {@link #controllers() controllers} are
|
||||
* defined), {@code @ControllerAdvice}, {@code WebInterceptor}
|
||||
* and {@code RuntimeWiringConfigurer} beans are
|
||||
* included.
|
||||
* @see #includeFilters()
|
||||
* @see #excludeFilters()
|
||||
* @return if default filters should be used
|
||||
*/
|
||||
boolean useDefaultFilters() default true;
|
||||
|
||||
/**
|
||||
* A set of include filters which can be used to add otherwise filtered beans to the
|
||||
* application context.
|
||||
* @return include filters to apply
|
||||
*/
|
||||
ComponentScan.Filter[] includeFilters() default {};
|
||||
|
||||
/**
|
||||
* A set of exclude filters which can be used to filter beans that would otherwise be
|
||||
* added to the application context.
|
||||
* @return exclude filters to apply
|
||||
*/
|
||||
ComponentScan.Filter[] excludeFilters() default {};
|
||||
|
||||
/**
|
||||
* Auto-configuration exclusions that should be applied for this test.
|
||||
* @return auto-configuration exclusions to apply
|
||||
*/
|
||||
@AliasFor(annotation = ImportAutoConfiguration.class, attribute = "exclude")
|
||||
Class<?>[] excludeAutoConfiguration() default {};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2020-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 org.springframework.graphql.boot.test;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.test.context.TestContextBootstrapper;
|
||||
|
||||
/**
|
||||
* {@link TestContextBootstrapper} for {@link GraphQlTest @GraphQlTest}
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class GraphQlTestContextBootstrapper extends SpringBootTestContextBootstrapper {
|
||||
|
||||
@Override
|
||||
protected String[] getProperties(Class<?> testClass) {
|
||||
return MergedAnnotations.from(testClass, MergedAnnotations.SearchStrategy.INHERITED_ANNOTATIONS).get(GraphQlTest.class)
|
||||
.getValue("properties", String[].class).orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2020-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 org.springframework.graphql.boot.test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
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.RuntimeWiringConfigurer;
|
||||
import org.springframework.graphql.web.WebInterceptor;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* {@link TypeExcludeFilter} for {@link GraphQlTest @GraphQlTest}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class GraphQlTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<GraphQlTest> {
|
||||
|
||||
private static final Class<?>[] NO_CONTROLLERS = {};
|
||||
|
||||
private static final String[] OPTIONAL_INCLUDES = { "com.fasterxml.jackson.databind.Module"};
|
||||
|
||||
private static final Set<Class<?>> DEFAULT_INCLUDES;
|
||||
|
||||
static {
|
||||
Set<Class<?>> includes = new LinkedHashSet<>();
|
||||
includes.add(JsonComponent.class);
|
||||
includes.add(RuntimeWiringConfigurer.class);
|
||||
includes.add(Converter.class);
|
||||
includes.add(GenericConverter.class);
|
||||
includes.add(WebInterceptor.class);
|
||||
for (String optionalInclude : OPTIONAL_INCLUDES) {
|
||||
try {
|
||||
includes.add(ClassUtils.forName(optionalInclude, null));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
DEFAULT_INCLUDES = Collections.unmodifiableSet(includes);
|
||||
}
|
||||
|
||||
private static final Set<Class<?>> DEFAULT_INCLUDES_AND_CONTROLLER;
|
||||
|
||||
static {
|
||||
Set<Class<?>> includes = new LinkedHashSet<>(DEFAULT_INCLUDES);
|
||||
includes.add(Controller.class);
|
||||
DEFAULT_INCLUDES_AND_CONTROLLER = Collections.unmodifiableSet(includes);
|
||||
}
|
||||
|
||||
private final Class<?>[] controllers;
|
||||
|
||||
GraphQlTypeExcludeFilter(Class<?> testClass) {
|
||||
super(testClass);
|
||||
this.controllers = getAnnotation().getValue("controllers", Class[].class).orElse(NO_CONTROLLERS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<Class<?>> getDefaultIncludes() {
|
||||
if (ObjectUtils.isEmpty(this.controllers)) {
|
||||
return DEFAULT_INCLUDES_AND_CONTROLLER;
|
||||
}
|
||||
return DEFAULT_INCLUDES;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<Class<?>> getComponentIncludes() {
|
||||
return new LinkedHashSet<>(Arrays.asList(this.controllers));
|
||||
}
|
||||
}
|
||||
@@ -24,20 +24,21 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.graphql.test.tester.GraphQlTester;
|
||||
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
||||
|
||||
/**
|
||||
* Annotation that can be applied to a test class to enable a {@link GraphQlTester}.
|
||||
* Annotation that can be applied to a test class to enable a {@link WebGraphQlTester}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @see GraphQlTesterAutoConfiguration
|
||||
* @since 1.0.0
|
||||
* @see WebTestClientMockMvcAutoConfiguration
|
||||
* @see WebGraphQlTesterAutoConfiguration
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@ImportAutoConfiguration
|
||||
public @interface AutoConfigureGraphQlTester {
|
||||
public @interface AutoConfigureWebGraphQlTester {
|
||||
|
||||
}
|
||||
@@ -16,37 +16,35 @@
|
||||
|
||||
package org.springframework.graphql.boot.test.tester;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.graphql.boot.GraphQlProperties;
|
||||
import org.springframework.graphql.test.tester.GraphQlTester;
|
||||
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* Auto-configuration for {@link GraphQlTester} in mock environments.
|
||||
* Configuration classes for {@link WebGraphQlTester}
|
||||
* <p>
|
||||
* Those should be {@code @Import} in a regular auto-configuration class to guarantee
|
||||
* their order of execution.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ WebClient.class, WebTestClient.class, GraphQlTester.class })
|
||||
@AutoConfigureAfter(value = WebTestClientMockMvcAutoConfiguration.class,
|
||||
name = "org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientAutoConfiguration")
|
||||
public class GraphQlTesterAutoConfiguration {
|
||||
class GraphQlTesterConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({WebClient.class, WebTestClient.class})
|
||||
@ConditionalOnBean(WebTestClient.class)
|
||||
public static class WebTestClientGraphQlTesterConfiguration {
|
||||
@ConditionalOnMissingBean(WebGraphQlTester.class)
|
||||
public static class WebTestClientConfig {
|
||||
|
||||
@Bean
|
||||
public WebGraphQlTester clientGraphQlTester(WebTestClient webTestClient, GraphQlProperties properties) {
|
||||
public WebGraphQlTester webTestClientGraphQlTester(WebTestClient webTestClient, GraphQlProperties properties) {
|
||||
WebTestClient mutatedWebTestClient = webTestClient.mutate().baseUrl(properties.getPath()).build();
|
||||
return WebGraphQlTester.create(mutatedWebTestClient);
|
||||
}
|
||||
@@ -54,13 +52,13 @@ public class GraphQlTesterAutoConfiguration {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(WebTestClient.class)
|
||||
@ConditionalOnBean(WebGraphQlHandler.class)
|
||||
public static class WebGraphQlHandlerGraphQlTesterConfiguration {
|
||||
@ConditionalOnMissingBean({WebGraphQlTester.class})
|
||||
public static class WebGraphQlHandlerConfig {
|
||||
|
||||
@Bean
|
||||
public WebGraphQlTester handlerGraphQlTester(WebGraphQlHandler handler) {
|
||||
return WebGraphQlTester.create(handler);
|
||||
public WebGraphQlTester webGraphQlTester(WebGraphQlHandler webGraphQlHandler) {
|
||||
return WebGraphQlTester.create(webGraphQlHandler);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2020-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 org.springframework.graphql.boot.test.tester;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.graphql.test.tester.GraphQlTester;
|
||||
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
||||
|
||||
/**
|
||||
* Auto-configuration for {@link WebGraphQlTester}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({GraphQlTester.class})
|
||||
@AutoConfigureAfter(value = WebTestClientMockMvcAutoConfiguration.class,
|
||||
name = "org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientAutoConfiguration")
|
||||
@Import({GraphQlTesterConfiguration.WebTestClientConfig.class, GraphQlTesterConfiguration.WebGraphQlHandlerConfig.class})
|
||||
public class WebGraphQlTesterAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.graphql.boot.GraphQlAutoConfiguration,\
|
||||
org.springframework.graphql.boot.GraphQlServiceAutoConfiguration,\
|
||||
org.springframework.graphql.boot.WebGraphQlHandlerAutoConfiguration,\
|
||||
org.springframework.graphql.boot.GraphQlWebFluxAutoConfiguration,\
|
||||
org.springframework.graphql.boot.GraphQlWebMvcAutoConfiguration,\
|
||||
org.springframework.graphql.boot.actuate.metrics.GraphQlMetricsAutoConfiguration,\
|
||||
@@ -14,10 +14,17 @@ org.springframework.boot.diagnostics.FailureAnalyzer=\
|
||||
org.springframework.graphql.boot.InvalidSchemaLocationsExceptionFailureAnalyzer
|
||||
|
||||
# Spring Test @AutoConfigureGraphQlTester
|
||||
org.springframework.graphql.boot.test.tester.AutoConfigureGraphQlTester=\
|
||||
org.springframework.graphql.boot.test.tester.AutoConfigureWebGraphQlTester=\
|
||||
org.springframework.graphql.boot.test.tester.WebTestClientMockMvcAutoConfiguration,\
|
||||
org.springframework.graphql.boot.test.tester.GraphQlTesterAutoConfiguration
|
||||
org.springframework.graphql.boot.test.tester.WebGraphQlTesterAutoConfiguration
|
||||
|
||||
# Spring Test ContextCustomizerFactories
|
||||
org.springframework.test.context.ContextCustomizerFactory=\
|
||||
org.springframework.graphql.boot.test.tester.GraphQlTesterContextCustomizerFactory
|
||||
org.springframework.graphql.boot.test.tester.GraphQlTesterContextCustomizerFactory
|
||||
|
||||
# AutoConfigureGraphQl auto-configuration imports
|
||||
org.springframework.graphql.boot.test.AutoConfigureGraphQl=\
|
||||
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
|
||||
org.springframework.graphql.boot.GraphQlAutoConfiguration,\
|
||||
org.springframework.graphql.boot.WebGraphQlHandlerAutoConfiguration
|
||||
@@ -46,7 +46,7 @@ class GraphQlWebFluxAutoConfigurationTests {
|
||||
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class,
|
||||
CodecsAutoConfiguration.class, JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class,
|
||||
GraphQlServiceAutoConfiguration.class, GraphQlWebFluxAutoConfiguration.class))
|
||||
WebGraphQlHandlerAutoConfiguration.class, GraphQlWebFluxAutoConfiguration.class))
|
||||
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)
|
||||
.withPropertyValues(
|
||||
"spring.main.web-application-type=reactive",
|
||||
|
||||
@@ -50,7 +50,7 @@ class GraphQlWebMvcAutoConfigurationTests {
|
||||
.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class,
|
||||
GraphQlServiceAutoConfiguration.class, GraphQlWebMvcAutoConfiguration.class))
|
||||
WebGraphQlHandlerAutoConfiguration.class, GraphQlWebMvcAutoConfiguration.class))
|
||||
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)
|
||||
.withPropertyValues(
|
||||
"spring.main.web-application-type=servlet",
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2020-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 org.springframework.graphql.boot;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;
|
||||
import org.springframework.graphql.execution.BatchLoaderRegistry;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link WebGraphQlHandlerAutoConfiguration}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class WebGraphQlHandlerAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(WebGraphQlHandlerAutoConfiguration.class))
|
||||
.withUserConfiguration(GraphQlSourceConfiguration.class);
|
||||
|
||||
@Test
|
||||
void shouldContributeStandardBeans() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasSingleBean(BatchLoaderRegistry.class);
|
||||
assertThat(context).hasSingleBean(GraphQlService.class);
|
||||
assertThat(context).hasSingleBean(AnnotatedControllerConfigurer.class);
|
||||
assertThat(context).hasSingleBean(WebGraphQlHandler.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class GraphQlSourceConfiguration {
|
||||
|
||||
@Bean
|
||||
GraphQlSource graphQlSource() {
|
||||
return mock(GraphQlSource.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,7 +35,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.graphql.boot.Book;
|
||||
import org.springframework.graphql.boot.GraphQlAutoConfiguration;
|
||||
import org.springframework.graphql.boot.GraphQlDataFetchers;
|
||||
import org.springframework.graphql.boot.GraphQlServiceAutoConfiguration;
|
||||
import org.springframework.graphql.boot.WebGraphQlHandlerAutoConfiguration;
|
||||
import org.springframework.graphql.boot.GraphQlWebFluxAutoConfiguration;
|
||||
import org.springframework.graphql.execution.ErrorType;
|
||||
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
|
||||
@@ -66,7 +66,7 @@ class GraphQlWebFluxSecurityAutoConfigurationTests {
|
||||
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class,
|
||||
CodecsAutoConfiguration.class, JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class,
|
||||
GraphQlServiceAutoConfiguration.class, GraphQlWebFluxAutoConfiguration.class,
|
||||
WebGraphQlHandlerAutoConfiguration.class, GraphQlWebFluxAutoConfiguration.class,
|
||||
GraphQlWebFluxSecurityAutoConfiguration.class, ReactiveSecurityAutoConfiguration.class))
|
||||
.withUserConfiguration(DataFetchersConfiguration.class, SecurityConfig.class)
|
||||
.withPropertyValues(
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.graphql.boot.Book;
|
||||
import org.springframework.graphql.boot.GraphQlAutoConfiguration;
|
||||
import org.springframework.graphql.boot.GraphQlDataFetchers;
|
||||
import org.springframework.graphql.boot.GraphQlServiceAutoConfiguration;
|
||||
import org.springframework.graphql.boot.WebGraphQlHandlerAutoConfiguration;
|
||||
import org.springframework.graphql.boot.GraphQlWebMvcAutoConfiguration;
|
||||
import org.springframework.graphql.execution.ErrorType;
|
||||
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
|
||||
@@ -71,7 +71,7 @@ class GraphQlWebMvcSecurityAutoConfigurationTests {
|
||||
.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class,
|
||||
GraphQlServiceAutoConfiguration.class, GraphQlWebMvcAutoConfiguration.class,
|
||||
WebGraphQlHandlerAutoConfiguration.class, GraphQlWebMvcAutoConfiguration.class,
|
||||
GraphQlWebMvcSecurityAutoConfiguration.class, SecurityAutoConfiguration.class))
|
||||
.withUserConfiguration(DataFetchersConfiguration.class, SecurityConfig.class)
|
||||
.withPropertyValues(
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2020-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 org.springframework.graphql.boot.test;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.boot.Book;
|
||||
import org.springframework.graphql.data.method.annotation.Argument;
|
||||
import org.springframework.graphql.data.method.annotation.QueryMapping;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
/**
|
||||
* Example {@code @Controller} to be tested with {@link GraphQlTest @GraphQlTest}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
@Controller
|
||||
public class BookController {
|
||||
|
||||
@QueryMapping
|
||||
public Book bookById(@Argument String id) {
|
||||
return new Book("42", "Sample Book", 100, "Jane Spring");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2020-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 org.springframework.graphql.boot.test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* Example {@link SpringBootApplication @SpringBootApplication} used with
|
||||
* {@link GraphQlTest @GraphQlTest} tests.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class ExampleGraphQlApplication {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2020-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 org.springframework.graphql.boot.test;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
||||
|
||||
/**
|
||||
* Integration test for {@link GraphQlTest @GraphQlTest} annotated tests.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
@GraphQlTest(controllers = BookController.class,
|
||||
properties = {"spring.graphql.schema.locations:classpath:books/"})
|
||||
public class GraphQlTestIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private WebGraphQlTester graphQlTester;
|
||||
|
||||
@Test
|
||||
void getBookdByIdShouldReturnTestBook() {
|
||||
String query = "{" +
|
||||
" bookById(id: \"book-1\"){ " +
|
||||
" id" +
|
||||
" name" +
|
||||
" pageCount" +
|
||||
" author" +
|
||||
" }" +
|
||||
"}";
|
||||
graphQlTester.query(query).execute()
|
||||
.path("data.bookById.id").entity(String.class).isEqualTo("42");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 2020-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 org.springframework.graphql.boot.test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import graphql.schema.idl.RuntimeWiring;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
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.RuntimeWiringConfigurer;
|
||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
import org.springframework.graphql.web.WebInput;
|
||||
import org.springframework.graphql.web.WebInterceptor;
|
||||
import org.springframework.graphql.web.WebInterceptorChain;
|
||||
import org.springframework.graphql.web.WebOutput;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
/**
|
||||
* Tests for {@link GraphQlTypeExcludeFilter}
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class GraphQlTypeExcludeFilterTests {
|
||||
|
||||
private MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
|
||||
|
||||
@Test
|
||||
void matchWhenHasNoControllers() throws Exception {
|
||||
GraphQlTypeExcludeFilter filter = new GraphQlTypeExcludeFilter(WithNoControllers.class);
|
||||
assertThat(excludes(filter, Controller1.class)).isFalse();
|
||||
assertThat(excludes(filter, Controller2.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleRuntimeWiringConfigurer.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleService.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleWebInterceptor.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleModule.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchWhenHasController() throws Exception {
|
||||
GraphQlTypeExcludeFilter filter = new GraphQlTypeExcludeFilter(WithController.class);
|
||||
assertThat(excludes(filter, Controller1.class)).isFalse();
|
||||
assertThat(excludes(filter, Controller2.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleRuntimeWiringConfigurer.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleService.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleWebInterceptor.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleModule.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchNotUsingDefaultFilters() throws Exception {
|
||||
GraphQlTypeExcludeFilter filter = new GraphQlTypeExcludeFilter(NotUsingDefaultFilters.class);
|
||||
assertThat(excludes(filter, Controller1.class)).isTrue();
|
||||
assertThat(excludes(filter, Controller2.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleRuntimeWiringConfigurer.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleService.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleWebInterceptor.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleModule.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchWithIncludeFilter() throws Exception {
|
||||
GraphQlTypeExcludeFilter filter = new GraphQlTypeExcludeFilter(WithIncludeFilter.class);
|
||||
assertThat(excludes(filter, Controller1.class)).isFalse();
|
||||
assertThat(excludes(filter, Controller2.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleRuntimeWiringConfigurer.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleService.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleRepository.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleWebInterceptor.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleModule.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchWithExcludeFilter() throws Exception {
|
||||
GraphQlTypeExcludeFilter filter = new GraphQlTypeExcludeFilter(WithExcludeFilter.class);
|
||||
assertThat(excludes(filter, Controller1.class)).isTrue();
|
||||
assertThat(excludes(filter, Controller2.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleRuntimeWiringConfigurer.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleService.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
|
||||
assertThat(excludes(filter, ExampleWebInterceptor.class)).isFalse();
|
||||
assertThat(excludes(filter, ExampleModule.class)).isFalse();
|
||||
}
|
||||
|
||||
private boolean excludes(GraphQlTypeExcludeFilter filter, Class<?> type) throws IOException {
|
||||
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type.getName());
|
||||
return filter.match(metadataReader, this.metadataReaderFactory);
|
||||
}
|
||||
|
||||
@GraphQlTest
|
||||
static class WithNoControllers {
|
||||
|
||||
}
|
||||
|
||||
@GraphQlTest(Controller1.class)
|
||||
static class WithController {
|
||||
|
||||
}
|
||||
|
||||
@GraphQlTest(useDefaultFilters = false)
|
||||
static class NotUsingDefaultFilters {
|
||||
|
||||
}
|
||||
|
||||
@GraphQlTest(includeFilters = @ComponentScan.Filter(Repository.class))
|
||||
static class WithIncludeFilter {
|
||||
|
||||
}
|
||||
|
||||
@GraphQlTest(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = Controller1.class))
|
||||
static class WithExcludeFilter {
|
||||
|
||||
}
|
||||
|
||||
@Controller
|
||||
static class Controller1 {
|
||||
|
||||
}
|
||||
|
||||
@Controller
|
||||
static class Controller2 {
|
||||
|
||||
}
|
||||
|
||||
@Service
|
||||
static class ExampleService {
|
||||
|
||||
}
|
||||
|
||||
@Repository
|
||||
static class ExampleRepository {
|
||||
|
||||
}
|
||||
|
||||
static class ExampleRuntimeWiringConfigurer implements RuntimeWiringConfigurer {
|
||||
@Override
|
||||
public void configure(RuntimeWiring.Builder builder) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class ExampleWebInterceptor implements WebInterceptor {
|
||||
|
||||
@Override
|
||||
public Mono<WebOutput> intercept(WebInput webInput, WebInterceptorChain chain) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class ExampleModule extends SimpleModule {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.graphql.boot.GraphQlProperties;
|
||||
import org.springframework.graphql.test.tester.GraphQlTester;
|
||||
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
@@ -34,20 +34,20 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link GraphQlTesterAutoConfiguration}
|
||||
* Tests for {@link WebGraphQlTesterAutoConfiguration}
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class GraphQlTesterAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(GraphQlTesterAutoConfiguration.class));
|
||||
.withConfiguration(AutoConfigurations.of(WebGraphQlTesterAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void shouldNotBeConfiguredWithoutGraphQlHandlerNorWebTestClient() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasNotFailed();
|
||||
assertThat(context).doesNotHaveBean(GraphQlTester.class);
|
||||
assertThat(context).doesNotHaveBean(WebGraphQlTester.class);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ class GraphQlTesterAutoConfigurationTests {
|
||||
void shouldBeConfiguredWhenGraphQlHandlerPresent() {
|
||||
this.contextRunner.withUserConfiguration(HandlerConfiguration.class).run((context) -> {
|
||||
assertThat(context).hasNotFailed();
|
||||
assertThat(context).hasSingleBean(GraphQlTester.class);
|
||||
assertThat(context).hasSingleBean(WebGraphQlTester.class);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class GraphQlTesterAutoConfigurationTests {
|
||||
void shouldBeConfiguredWhenWebTestClientPresent() {
|
||||
this.contextRunner.withUserConfiguration(WebTestClientConfiguration.class).run((context) -> {
|
||||
assertThat(context).hasNotFailed();
|
||||
assertThat(context).hasSingleBean(GraphQlTester.class);
|
||||
assertThat(context).hasSingleBean(WebGraphQlTester.class);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.graphql.boot.test.tester.AutoConfigureGraphQlTester;
|
||||
import org.springframework.graphql.boot.test.tester.AutoConfigureWebGraphQlTester;
|
||||
import org.springframework.graphql.execution.ErrorType;
|
||||
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
||||
|
||||
@@ -29,7 +29,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
@SpringBootTest()
|
||||
@AutoConfigureWebTestClient
|
||||
@AutoConfigureGraphQlTester
|
||||
@AutoConfigureWebGraphQlTester
|
||||
class SampleApplicationTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -4,7 +4,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.graphql.boot.test.tester.AutoConfigureGraphQlTester;
|
||||
import org.springframework.graphql.boot.test.tester.AutoConfigureWebGraphQlTester;
|
||||
import org.springframework.graphql.execution.ErrorType;
|
||||
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
||||
|
||||
@@ -13,7 +13,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
@AutoConfigureGraphQlTester
|
||||
@AutoConfigureWebGraphQlTester
|
||||
class SampleApplicationTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.graphql.boot.test.tester.AutoConfigureGraphQlTester;
|
||||
import org.springframework.graphql.boot.test.tester.AutoConfigureWebGraphQlTester;
|
||||
import org.springframework.graphql.test.tester.GraphQlTester;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
@@ -31,7 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
@AutoConfigureGraphQlTester
|
||||
@AutoConfigureWebGraphQlTester
|
||||
public class MockMvcGraphQlTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -119,7 +119,7 @@ spring.graphql.schema.printer.enabled=false
|
||||
The GraphQL Java `RuntimeWiring.Builder` can be used to register ``DataFetcher``s,
|
||||
type resolvers, custom scalar types, and more. You can declare `RuntimeWiringConfigurer`
|
||||
beans in your Spring config to get access to the `RuntimeWiring.Builder`. The Boot
|
||||
starter detects such beans adds them to <<index#execution-graphqlsource,GraphQlSource.Builder>>.
|
||||
starter detects such beans and adds them to <<index#execution-graphqlsource,GraphQlSource.Builder>>.
|
||||
|
||||
Typically, however, applications will not implement ``DataFetcher`` directly and will
|
||||
instead create <<index#controllers,annotated controllers>>. The Boot
|
||||
@@ -364,8 +364,12 @@ A GraphQL error metric counter is available at `/actuator/metrics/graphql.error`
|
||||
[[boot-graphql-testing]]
|
||||
== Testing
|
||||
|
||||
For Spring GraphQL testing support, add the below to your classpath and that will make
|
||||
a `WebGraphQlTester` available for injection into tests:
|
||||
Spring GraphQL offers many ways to test your application: with or without a live server, using the transport
|
||||
or testing directly the engine. You'll be using a lot the <<testing#testing-webgraphqltester,WebGraphQlTester>>,
|
||||
so make sure you're familiar with it before writing your first test.
|
||||
|
||||
The Spring Boot starter will help you and configure the testing infrastructure; all you to start
|
||||
is to add the following to your classpath:
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,quotes,attributes",role="primary"]
|
||||
.Gradle
|
||||
@@ -374,7 +378,7 @@ dependencies {
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testImplementation 'org.springframework.graphql:spring-graphql-test:{spring-graphql-version}'
|
||||
|
||||
// Also add this, unless `spring-boot-starter-webflux` is also present
|
||||
// Also add this, unless spring-boot-starter-webflux is also present
|
||||
testImplementation 'org.springframework:spring-webflux'
|
||||
|
||||
// ...
|
||||
@@ -432,6 +436,89 @@ repositories {
|
||||
</repositories>
|
||||
----
|
||||
|
||||
In the next sections, we'll see the various options available for testing your Spring GraphQL application.
|
||||
|
||||
[[boot-graphql-testing-graphqltest]]
|
||||
=== Testing GraphQL components only
|
||||
|
||||
You can test your Spring GraphQL `@Controller` and GraphQL components with the `@GraphQlTest` annotation.
|
||||
`@GraphQlTest` auto-configures the Spring GraphQL infrastructure ad limits scanned beans to `@Controller`,
|
||||
`RuntimeWiringConfigurer`, `JsonComponent`, `WebInterceptor`, `Converter`, `GenericConverter`
|
||||
Regular `@Component` and `@ConfigurationProperties` beans are not scanned when the `@GraphQlTest` annotation is used.
|
||||
`@EnableConfigurationProperties` can be used to include `@ConfigurationProperties` beans.
|
||||
|
||||
This arrangement is quite similar to the
|
||||
{spring-boot-ref-docs}/features.html#features.testing.spring-boot-applications.spring-mvc-tests[@WevMvcTest support],
|
||||
except that the web framework of choice (Spring MVC or Spring WebFlux) is not involved at all as requests are performed
|
||||
directly against the `WebGraphQlHandler`.
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@GraphQlTest(controllers = BookController.class)
|
||||
public class BookControllerTests {
|
||||
|
||||
@Autowired
|
||||
private WebGraphQlTester graphQlTester;
|
||||
|
||||
@MockBean
|
||||
private BookRepository bookRepository;
|
||||
|
||||
@Test
|
||||
void bookdByIdShouldReturnSpringBook() {
|
||||
given(this.bookRepository.findById(42L)).willReturn(new Book(42L, "Spring GraphQL"));
|
||||
String query = //
|
||||
graphQlTester.query(query).execute()
|
||||
.path("data.bookById.name").entity(String.class).isEqualTo("Spring GraphQL");
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
This mode is also useful for testing subscriptions without involving the transport protocol.
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@GraphQlTest(controllers = GreetingController.class)
|
||||
public class GreetingControllerTests {
|
||||
|
||||
@Autowired
|
||||
private WebGraphQlTester graphQlTester;
|
||||
|
||||
@Test
|
||||
void subscription() {
|
||||
Flux<String> result = this.graphQlTester.query("subscription { greetings }")
|
||||
.executeSubscription()
|
||||
.toFlux("greetings", String.class);
|
||||
|
||||
// Use StepVerifier from "reactor-test" to verify the stream...
|
||||
StepVerifier.create(result)
|
||||
.expectNext("Hi")
|
||||
.expectNext("Bonjour")
|
||||
.expectNext("Hola")
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
The above subscription test is performed directly against the `WebGraphQlHandler` that
|
||||
both HTTP and WebSocket transports delegate to. It passes through the `WebInterceptor`
|
||||
chain and then calls GraphQL Java 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, `@GraphQlTest` supports testing multiple controllers with its `controllers` annotation attribute.
|
||||
====
|
||||
|
||||
[[boot-graphql-testing-mock]]
|
||||
=== Testing the HTTP transport with a Mock server
|
||||
|
||||
If your test requires more integration with application components, you can choose to test the entire
|
||||
application and involve the transport layers and the Web framework.
|
||||
|
||||
For GraphQL over HTTP with Spring MVC, using `MockMvc` as the server:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
@@ -463,13 +550,18 @@ public class MockMvcGraphQlTests {
|
||||
}
|
||||
----
|
||||
|
||||
For GraphQL over HTTP with a
|
||||
{spring-boot-ref-docs}/features.html#features.testing.spring-boot-applications.with-running-server[running server]:
|
||||
|
||||
|
||||
[[boot-graphql-testing-live]]
|
||||
=== Testing the HTTP transport with a live server
|
||||
|
||||
You can also run tests against the full application infrastructure, including a live server.
|
||||
Just like {spring-boot-ref-docs}/features.html#features.testing.spring-boot-applications.with-running-server[REST endpoints testing],
|
||||
you can use a `WebEnvironment.RANDOM_PORT` environment and test queries using `WebGraphQlTester`.
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureGraphQlTester
|
||||
public class MockMvcGraphQlTests {
|
||||
|
||||
@Autowired
|
||||
@@ -477,35 +569,3 @@ public class MockMvcGraphQlTests {
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
Subscriptions can be tested without WebSocket as shown below:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@SpringBootTest
|
||||
@AutoConfigureGraphQlTester
|
||||
public class MockMvcGraphQlTests {
|
||||
|
||||
@Autowired
|
||||
private WebGraphQlTester graphQlTester;
|
||||
|
||||
@Test
|
||||
void subscription() {
|
||||
Flux<String> result = this.graphQlTester.query("subscription { greetings }")
|
||||
.executeSubscription()
|
||||
.toFlux("greetings", String.class);
|
||||
|
||||
// Use StepVerifier from "reactor-test" to verify the stream...
|
||||
StepVerifier.create(result)
|
||||
.expectNext("Hi")
|
||||
.expectNext("Bonjour")
|
||||
.expectNext("Hola")
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
The above subscription test is performed directly against the `WebGraphQlHandler` that
|
||||
both HTTP and WebSocket transports delegate to. It passes through the `WebInterceptor`
|
||||
chain and then calls GraphQL Java which returns a Reactive Streams `Publisher`.
|
||||
|
||||
@@ -24,8 +24,8 @@ import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
/**
|
||||
* Main entry point for testing GraphQL over a Web transport with requests
|
||||
* executed {@link #create(WebTestClient) via WebTestClient} or
|
||||
* {@link #create(WebGraphQlHandler) via WebGraphQlHandler}. See the below for
|
||||
* examples with different scenarios.
|
||||
* {@link #create(WebGraphQlHandler) via WebGraphQlHandler}.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* GraphQL requests to Spring MVC without an HTTP server: <pre class="code">
|
||||
|
||||
Reference in New Issue
Block a user