測試

Spring for GraphQL 提供了專門的支援,用於透過 HTTP、WebSocket 和 RSocket 測試 GraphQL 請求,以及直接針對伺服器進行測試。

要使用此功能,請將 spring-graphql-test 新增到您的構建中

  • Gradle

  • Maven

dependencies {
	// ...
	testImplementation 'org.springframework.graphql:spring-graphql-test:2.0.0'
}
<dependencies>
	<!-- ... -->
	<dependency>
		<groupId>org.springframework.graphql</groupId>
		<artifactId>spring-graphql-test</artifactId>
		<version>2.0.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 配置

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("https://:8080/graphql")
				.build();

HttpGraphQlTester tester = HttpGraphQlTester.create(client);

一旦建立了 HttpGraphQlTester,您就可以開始使用相同的 API 執行請求,而無需考慮底層傳輸。如果需要更改任何特定於傳輸的詳細資訊,請在現有 HttpSocketGraphQlTester 上使用 mutate() 建立具有自定義設定的新例項

WebTestClient.Builder clientBuilder =
		WebTestClient.bindToServer()
				.baseUrl("https://: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...

WebSocket

WebSocketGraphQlTester 透過共享的 WebSocket 連線執行 GraphQL 請求。它使用 Spring WebFlux 中的 WebSocketClient 構建,您可以按如下方式建立它

String url = "https://:8080/graphql";
WebSocketClient client = new ReactorNettyWebSocketClient();

WebSocketGraphQlTester tester = WebSocketGraphQlTester.builder(url, client).build();

WebSocketGraphQlTester 是面向連線和多路複用的。每個例項都為其所有請求建立自己的單一共享連線。通常,您會希望每個伺服器只使用一個例項。

一旦建立了 WebSocketGraphQlTester,您就可以開始使用相同的 API 執行請求,而無需考慮底層傳輸。如果需要更改任何特定於傳輸的詳細資訊,請在現有 WebSocketGraphQlTester 上使用 mutate() 建立具有自定義設定的新例項

URI url = URI.create("ws://: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 連線,例如在測試執行之後。

RSocket

RSocketGraphQlTester 使用 spring-messaging 中的 RSocketRequester 透過 RSocket 執行 GraphQL 請求

URI url = URI.create("wss://: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-test/" 下建立副檔名為 .graphql.gql 的文件檔案,並按檔名引用它們。

例如,給定一個名為 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 變數。

此方法也適用於為您的查詢載入片段。片段是可重用的欄位選擇集,可避免請求文件中的重複。例如,我們可以在多個查詢中使用 …​releases 片段

src/main/resources/graphql-documents/projectReleases.graphql
query frameworkReleases {
	project(slug: "spring-framework") {
		name
		...releases
	}
}
query graphqlReleases {
       project(slug: "spring-graphql") {
           name
           ...releases
       }
   }

此片段可以定義在單獨的檔案中以供重用

src/main/resources/graphql-documents/releases.graphql
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 響應的“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,或伺服器端 ExecutionGraphQlServiceWebGraphQlHandler 擴充套件。

錯誤

當您使用 verify() 時,響應中“errors”鍵下的任何錯誤都會導致斷言失敗。要抑制特定錯誤,請在 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 檢查所有錯誤,這樣做也會將它們標記為已過濾,因此您也可以檢查響應中的資料

graphQlTester.document(document)
		.execute()
		.errors()
		.satisfy((errors) ->
				assertThat(errors)
						.anyMatch((error) -> error.getMessage().contains("ignored error"))
		);
© . This site is unofficial and not affiliated with VMware.