| 此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring GraphQL 1.4.1! | 
测试
Spring for GraphQL 为通过 HTTP、WebSocket 和 RSocket 测试 GraphQL 请求以及直接针对服务器进行测试提供了专门的支持。
要利用这一点,请添加spring-graphql-test到你的构建:
- 
Gradle 
- 
Maven 
dependencies {
	// ...
	testImplementation 'org.springframework.graphql:spring-graphql-test:2.0.0-SNAPSHOT'
}<dependencies>
	<!-- ... -->
	<dependency>
		<groupId>org.springframework.graphql</groupId>
		<artifactId>spring-graphql-test</artifactId>
		<version>2.0.0-SNAPSHOT</version>
		<scope>test</scope>
	</dependency>
</dependencies>GraphQlTester
GraphQlTester是一个合约,声明了用于测试 GraphQL 的通用工作流程独立于底层传输的请求。这意味着请求经过测试使用相同的 API,无论底层传输是什么,以及任何传输特定是在构建时配置的。
要创建GraphQlTester通过客户端执行请求,则需要以下扩展名之一:
要创建GraphQlTester在服务器端执行测试,无需客户端:
每个定义了一个Builder具有与传输相关的选项。所有构建器都扩展了从通用的基础 GraphQlTesterBuilder跟 与所有扩展相关的选项。
HTTP
HttpGraphQlTester使用 WebTestClient 执行通过 HTTP 执行 GraphQL 请求,无论是否使用实时服务器,具体取决于方式WebTestClient已配置。
要在没有实时服务器的情况下在 Spring WebFlux 中进行测试,请指向声明 GraphQL HTTP 端点的 Spring 配置:
AnnotationConfigWebApplicationContext context = ...
WebTestClient client =
		WebTestClient.bindToApplicationContext(context)
				.configureClient()
				.baseUrl("/graphql")
				.build();
HttpGraphQlTester tester = HttpGraphQlTester.create(client);要在没有实时服务器的情况下在 Spring MVC 中进行测试,请使用MockMvcWebTestClient:
AnnotationConfigWebApplicationContext context = ...
WebTestClient client =
		MockMvcWebTestClient.bindToApplicationContext(context)
				.configureClient()
				.baseUrl("/graphql")
				.build();
HttpGraphQlTester tester = HttpGraphQlTester.create(client);或者针对在端口上运行的实时服务器进行测试:
WebTestClient client =
		WebTestClient.bindToServer()
				.baseUrl("http://localhost:8080/graphql")
				.build();
HttpGraphQlTester tester = HttpGraphQlTester.create(client);一次HttpGraphQlTester创建时,您可以开始使用相同的 API 执行请求,而不受底层 运输。 如果您需要更改任何特定于传输的详细信息,请使用mutate()在 现存HttpSocketGraphQlTester要使用自定义设置创建新实例,请执行以下作:
WebTestClient.Builder clientBuilder =
		WebTestClient.bindToServer()
				.baseUrl("http://localhost:8080/graphql");
HttpGraphQlTester tester = HttpGraphQlTester.builder(clientBuilder)
		.headers((headers) -> headers.setBasicAuth("joe", "..."))
		.build();
// Use tester...
HttpGraphQlTester anotherTester = tester.mutate()
		.headers((headers) -> headers.setBasicAuth("peter", "..."))
		.build();
// Use anotherTester...Web套接字
WebSocketGraphQlTester通过共享的 WebSocket 连接执行 GraphQL 请求。它是使用 Spring WebFlux 中的 WebSocketClient 构建的,您可以按如下方式创建它:
String url = "http://localhost:8080/graphql";
WebSocketClient client = new ReactorNettyWebSocketClient();
WebSocketGraphQlTester tester = WebSocketGraphQlTester.builder(url, client).build();WebSocketGraphQlTester是面向连接和多路复用的。每个实例都会建立它自己的单个共享连接用于所有请求。通常,您需要使用单个每个服务器仅实例。
一次WebSocketGraphQlTester创建时,您可以开始使用相同的 API 执行请求,而不受底层 运输。 如果您需要更改任何特定于传输的详细信息,请使用mutate()在 现存WebSocketGraphQlTester要使用自定义设置创建新实例,请执行以下作:
URI url = URI.create("ws://localhost:8080/graphql");
WebSocketClient client = new ReactorNettyWebSocketClient();
WebSocketGraphQlTester tester = WebSocketGraphQlTester.builder(url, client)
		.headers((headers) -> headers.setBasicAuth("joe", "..."))
		.build();
// Use tester...
WebSocketGraphQlTester anotherTester = tester.mutate()
		.headers((headers) -> headers.setBasicAuth("peter", "..."))
		.build();
// Use anotherTester...WebSocketGraphQlTester提供一个stop()方法,您可以使用该方法来关闭 WebSocket连接,例如在测试运行后。
RS袜子
RSocketGraphQlTester使用RSocketRequester从 spring-messaging 执行 GraphQL通过 RSocket 的请求:
URI url = URI.create("wss://localhost:8080/rsocket");
WebsocketClientTransport transport = WebsocketClientTransport.create(url);
RSocketGraphQlTester client = RSocketGraphQlTester.builder()
		.clientTransport(transport)
		.build();RSocketGraphQlTester面向连接和多路复用。每个实例都建立
它自己的单个共享会话用于所有请求。通常,您需要使用单个
仅每个服务器的实例。您可以使用stop()方法关闭
会话显式。
一次RSocketGraphQlTester创建时,您可以开始使用相同的 API 执行请求,而不受底层
运输。
ExecutionGraphQlService
很多时候,在服务器端测试 GraphQL 请求就足够了,而无需使用
客户端通过传输协议发送请求。直接针对ExecutionGraphQlService,使用ExecutionGraphQlServiceTester外延:
ExecutionGraphQlService service = ...
ExecutionGraphQlServiceTester tester = ExecutionGraphQlServiceTester.create(service);一次ExecutionGraphQlServiceTester创建时,您可以开始使用相同的 API 执行请求,而不受底层
运输。
ExecutionGraphQlServiceTester.Builder提供自定义选项ExecutionInput详:
ExecutionGraphQlService service = ...
ExecutionId executionId = ExecutionId.generate();
ExecutionGraphQlServiceTester tester = ExecutionGraphQlServiceTester.builder(service)
		.configureExecutionInput((executionInput, builder) -> builder.executionId(executionId).build())
		.build();WebGraphQlHandler
这ExecutionGraphQlService扩展允许您在服务器端进行测试,而无需
一个客户。但是,在某些情况下,涉及服务器端传输很有用
使用给定的模拟传输输入进行处理。
这WebGraphQlTester扩展允许您通过WebGraphQlInterceptor链条,然后移交给ExecutionGraphQlService为
请求执行:
WebGraphQlHandler handler = ...
WebGraphQlTester tester = WebGraphQlTester.create(handler);此扩展的构建器允许您定义 HTTP 请求详细信息:
WebGraphQlHandler handler = ...
WebGraphQlTester tester = WebGraphQlTester.builder(handler)
		.headers((headers) -> headers.setBasicAuth("joe", "..."))
		.build();一次WebGraphQlTester创建时,您可以开始使用相同的 API 执行请求,而不受底层传输的影响。
架构工人
GraphQlTester定义父级Builder为所有受支持的传输的构建者提供通用配置选项。
它允许您配置以下内容:
- 
errorFilter- 用于抑制预期错误的谓词,以便您可以检查数据 的回应。
- 
documentSource- 从文件加载请求的文档的策略 类路径或其他任何位置。
- 
responseTimeout- 在计时之前等待请求执行完成多长时间 外。
GraphQlTransport transport = ...
Predicate<ResponseError> errorFilter = ...
ClassPathResource resource = new ClassPathResource("custom-folder/");
DocumentSource documentSource = new ResourceDocumentSource(resource);
GraphQlTester tester = GraphQlTester.builder(transport)
		.documentSource(documentSource)
		.errorFilter(errorFilter)
		.responseTimeout(Duration.ofSeconds(5))
		.build();请求
一旦你有一个GraphQlTester,您可以开始测试请求。下面执行一个
查询项目,并使用 JsonPath 提取
响应中的项目发布版本:
String document =
		"""
		{
			project(slug:"spring-framework") {
				releases {
				version
				}
			}
		}
		""";
graphQlTester.document(document)
		.execute()
		.path("project.releases[*].version")
		.entityList(String.class)
		.hasSizeGreaterThan(1);JsonPath 相对于响应的“data”部分。
您还可以创建带有扩展名的文档文件.graphql或.gql下"graphql-test/"并按文件名引用它们。
例如,给定一个名为projectReleases.graphql在src/main/resources/graphql-test,内容:
query projectReleases($slug: ID!) {
	project(slug: $slug) {
		releases {
			version
		}
	}
}然后,您可以使用:
graphQlTester.documentName("projectReleases") (1)
		.variable("slug", "spring-framework") (2)
		.execute()
		.path("projectReleases.project.releases[*].version")
		.entityList(String.class)
		.hasSizeGreaterThan(1);| 1 | 请参阅名为“project”的文件中的文档。 | 
| 2 | 将 slug变量。 | 
此方法也适用于加载查询的片段。
片段是可重用的字段选择集,可避免在请求文档中重复。
例如,我们可以使用…releasesfragment 在多个查询中:
query frameworkReleases {
	project(slug: "spring-framework") {
		name
		...releases
	}
}
query graphqlReleases {
       project(slug: "spring-graphql") {
           name
           ...releases
       }
   }可以在单独的文件中定义此片段以供重用:
fragment releases on Project {
   	releases {
           version
       }
   }然后,您可以沿着查询文档发送此片段:
graphQlTester.documentName("projectReleases") (1)
		.fragmentName("releases") (2)
		.execute()
		.path("frameworkReleases.project.releases[*].version")
		.entityList(String.class)
		.hasSizeGreaterThan(1);| 1 | 从“projectReleases.graphql”加载文档 | 
| 2 | 从“releases.graphql”加载片段并将其附加到文档中 | 
| IntelliJ 的“JS GraphQL”插件支持具有代码补全功能的 GraphQL 查询文件。 | 
如果请求没有任何响应数据,例如突变,请使用executeAndVerify而不是execute要验证响应中没有错误,请执行以下作:
graphQlTester.query(query).executeAndVerify();有关错误处理的更多详细信息,请参阅错误。
嵌套路径
默认情况下,路径相对于 GraphQL 响应的“数据”部分。您还可以 嵌套到路径,并检查相对于它的多个路径,如下所示:
graphQlTester.document(document)
		.execute()
		.path("project", (project) -> project (1)
				.path("name").entity(String.class).isEqualTo("spring-framework")
				.path("releases[*].version").entityList(String.class).hasSizeGreaterThan(1));| 1 | 使用回调检查相对于“project”的路径。 | 
订阅
若要测试订阅,请调用executeSubscription而不是execute获取流
的响应,然后使用StepVerifier从 Project Reactor 检查流:
Flux<String> greetingFlux = tester.document("subscription { greetings }")
		.executeSubscription()
		.toFlux("greetings", String.class);  // decode at JSONPath
StepVerifier.create(greetingFlux)
		.expectNext("Hi")
		.expectNext("Bonjour")
		.expectNext("Hola")
		.verifyComplete();订阅仅支持 WebSocketGraphQlTester 或服务器端ExecutionGraphQlService和WebGraphQlHandler扩展。
错误
当您使用verify(),响应中“error”键下的任何错误都会导致
断言失败。若要禁止显示特定错误,请在verify():
graphQlTester.document(query)
		.execute()
		.errors()
		.filter((error) -> error.getMessage().equals("ignored error"))
		.verify()
		.path("project.releases[*].version")
		.entityList(String.class)
		.hasSizeGreaterThan(1);您可以在构建器级别注册错误过滤器,以应用于所有测试:
WebGraphQlTester graphQlTester = WebGraphQlTester.builder(handler)
		.errorFilter((error) -> error.getMessage().equals("ignored error"))
		.build();如果要验证错误是否存在,并且与filter,抛出一个
断言错误如果没有,则使用expect相反:
graphQlTester.document(query)
		.execute()
		.errors()
		.expect((error) -> error.getMessage().equals("expected error"))
		.verify()
		.path("project.releases[*].version")
		.entityList(String.class)
		.hasSizeGreaterThan(1);您还可以通过Consumer,并且这样做也会将它们标记为
filtered,因此您还可以检查响应中的数据:
graphQlTester.document(document)
		.execute()
		.errors()
		.satisfy((errors) ->
				assertThat(errors)
						.anyMatch((error) -> error.getMessage().contains("ignored error"))
		);