测试
Spring for GraphQL 提供了专门的支持,用于测试通过 HTTP、WebSocket 和 RSocket 的 GraphQL 请求,以及直接针对服务器进行测试。
要使用此功能,请将 spring-graphql-test
添加到您的构建中
-
Gradle
-
Maven
dependencies {
// ...
testImplementation 'org.springframework.graphql:spring-graphql-test:1.3.0'
}
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql-test</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
</dependencies>
GraphQlTester
GraphQlTester
是一个契约,它声明了一种用于测试 GraphQL 请求的通用工作流程,该流程独立于底层传输。这意味着请求使用相同的 API 进行测试,无论底层传输是什么,并且任何特定于传输的内容都在构建时配置。
要创建一个通过客户端执行请求的 GraphQlTester
,您需要以下扩展之一
要创建一个在服务器端执行测试的 GraphQlTester
,无需客户端
每个都定义了一个 Builder
,其中包含与传输相关的选项。所有构建器都从一个通用的基本 GraphQlTester Builder
扩展,该构建器包含与所有扩展相关的选项。
HTTP
HttpGraphQlTester
使用 WebTestClient 通过 HTTP 执行 GraphQL 请求,无论是否有实时服务器,具体取决于 WebTestClient
的配置方式。
要在 Spring WebFlux 中进行测试,无需实时服务器,请指向声明 GraphQL HTTP 端点的 Spring 配置
ApplicationContext context = ... ;
WebTestClient client =
WebTestClient.bindToApplicationContext(context)
.configureClient()
.baseUrl("/graphql")
.build();
HttpGraphQlTester tester = HttpGraphQlTester.create(client);
要在 Spring MVC 中进行测试,无需实时服务器,请使用 MockMvcWebTestClient
执行相同的操作
ApplicationContext context = ... ;
WebTestClient client =
MockMvcWebTestClient.bindToApplicationContext(context)
.configureClient()
.baseUrl("/graphql")
.build();
HttpGraphQlTester tester = HttpGraphQlTester.create(client);
或者,要针对在端口上运行的实时服务器进行测试
WebTestClient client =
WebTestClient.bindToServer()
.baseUrl("https://127.0.0.1:8080/graphql")
.build();
HttpGraphQlTester tester = HttpGraphQlTester.create(client);
创建 HttpGraphQlTester
后,您可以开始使用相同的 API 执行请求,与底层传输无关。如果您需要更改任何特定于传输的详细信息,请在现有 HttpSocketGraphQlTester
上使用 mutate()
创建一个具有自定义设置的新实例
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...
WebSocket
WebSocketGraphQlTester
通过共享 WebSocket 连接执行 GraphQL 请求。它使用 Spring WebFlux 中的 WebSocketClient 构建,您可以按如下方式创建它
String url = "https://127.0.0.1:8080/graphql";
WebSocketClient client = new ReactorNettyWebSocketClient();
WebSocketGraphQlTester tester = WebSocketGraphQlTester.builder(url, client).build();
WebSocketGraphQlTester
是面向连接的,并且是多路复用的。每个实例都为所有请求建立自己的单个共享连接。通常,您只希望每个服务器使用一个实例。
创建 WebSocketGraphQlTester
后,您可以开始使用相同的 API 执行请求,与底层传输无关。如果您需要更改任何特定于传输的详细信息,请在现有 WebSocketGraphQlTester
上使用 mutate()
创建一个具有自定义设置的新实例
URI url = ... ;
WebSocketClient client = ... ;
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 连接,例如在测试运行后。
RSocket
RSocketGraphQlTester
使用 spring-messaging 中的 RSocketRequester
通过 RSocket 执行 GraphQL 请求
URI uri = URI.create("wss://127.0.0.1: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 = ... ;
ExecutionGraphQlServiceTester tester = ExecutionGraphQlServiceTester.builder(service)
.configureExecutionInput((executionInput, builder) -> builder.executionId(id).build())
.build();
WebGraphQlHandler
ExecutionGraphQlService
扩展允许您在服务器端进行测试,无需客户端。但是,在某些情况下,使用给定的模拟传输输入来涉及服务器端传输处理会很有用。
WebGraphQlTester
扩展允许您在将请求传递给 ExecutionGraphQlService
以执行请求之前,通过 WebGraphQlInterceptor
链处理请求。
WebGraphQlHandler handler = ... ;
WebGraphQlTester tester = WebGraphQlTester.create(handler);
此扩展的构建器允许您定义 HTTP 请求详细信息。
WebGraphQlHandler handler = ... ;
WebGraphQlTester tester = WebGraphQlTester.builder(handler)
.headers(headers -> headers.setBasicAuth("joe", "..."))
.build();
创建 WebGraphQlTester
后,您可以开始使用相同的 API 执行请求,与底层传输无关。
Requests
拥有 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/"
下,并通过文件名引用它们。
例如,假设在 src/main/resources/graphql-test
中有一个名为 projectReleases.graphql
的文件,其内容为:
query projectReleases($slug: ID!) {
project(slug: $slug) {
releases {
version
}
}
}
然后您可以使用:
graphQlTester.documentName("projectReleases") (1)
.variable("slug", "spring-framework") (2)
.execute()
.path("project.releases[*].version")
.entityList(String.class)
.hasSizeGreaterThan(1);
1 | 引用名为“project”的文件中的文档。 |
2 | 设置 slug 变量。 |
IntelliJ 的“JS GraphQL”插件支持带有代码补全功能的 GraphQL 查询文件。 |
如果请求没有响应数据,例如突变,请使用executeAndVerify
而不是execute
来验证响应中没有错误。
graphQlTester.query(query).executeAndVerify();
有关错误处理的更多详细信息,请参见错误。
嵌套路径
默认情况下,路径相对于 GraphQL 响应的“data”部分。您也可以嵌套到某个路径,并检查相对于该路径的多个路径,如下所示
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
来获取响应流,然后使用 Project Reactor 的StepVerifier
来检查流。
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()
时,响应中“errors”键下的任何错误都会导致断言失败。要抑制特定错误,请在verify()
之前使用错误过滤器。
graphQlTester.query(query)
.execute()
.errors()
.filter(error -> ...)
.verify()
.path("project.releases[*].version")
.entityList(String.class)
.hasSizeGreaterThan(1);
您可以在构建器级别注册错误过滤器,以将其应用于所有测试。
WebGraphQlTester graphQlTester = WebGraphQlTester.builder(client)
.errorFilter(error -> ...)
.build();
如果您想验证错误确实存在,并且与filter
相反,如果错误不存在,则抛出断言错误,那么请使用expect
代替。
graphQlTester.query(query)
.execute()
.errors()
.expect(error -> ...)
.verify()
.path("project.releases[*].version")
.entityList(String.class)
.hasSizeGreaterThan(1);
您也可以通过Consumer
检查所有错误,这样做也会将它们标记为已过滤,因此您也可以检查响应中的数据。
graphQlTester.query(query)
.execute()
.errors()
.satisfy(errors -> {
// ...
});