GraphQL APIの結合テスト
GraphQL API全体の結合テストを実施し、Query、Mutation、Subscriptionをエンドツーエンドで検証します。
「GraphQL APIの結合テスト」はCoddyKit上の無料GraphQL APIs with Spring Bootレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGraphQL APIs with Spring Boot学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 GraphQL APIs with Spring Bootコースには全4レッスンが含まれています。
このレッスンの一部はまだ翻訳されておらず、英語で表示されています。
Why Integration Test GraphQL?
Welcome to integration testing for GraphQL APIs! While unit tests check small parts of your code, integration tests verify that different components work together correctly.
- End-to-End Flow: They simulate real client requests.
- Component Interaction: Ensure your GraphQL schema, resolvers, and data sources all connect properly.
- Confidence: Gives you assurance that your API behaves as expected before deployment.
This lesson focuses on using Spring Boot's testing utilities.
Essential Spring Boot Test Tools
Spring Boot provides powerful tools to make integration testing straightforward:
@SpringBootTest: This annotation loads your full application context, making all your beans available for testing.WebTestClient: A non-blocking client for testing web endpoints. It simulates HTTP requests to your GraphQL API.
Together, these allow you to send actual GraphQL queries/mutations and inspect the responses.
Setting Up Your Test Class
To start, you'll create a test class. Annotate it with @SpringBootTest to load your application context. Then, inject WebTestClient to interact with your GraphQL endpoint.
We typically use @AutoConfigureWebTestClient to configure WebTestClient for testing, often with a specific port or context path.
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.test.web.reactive.server.WebTestClient;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class GraphQLIntegrationTest {
@Autowired
private WebTestClient webTestClient;
// Your test methods will go here
}Crafting a Simple Query Test
Let's write a test for a basic GraphQL query. We'll define the query string and then use WebTestClient to send it to the /graphql endpoint.
The query will be sent as a JSON payload in the request body, typically containing a query field and optionally variables.
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.test.web.reactive.server.WebTestClient;
import java.util.Map;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class SampleQueryTest {
@Autowired
private WebTestClient webTestClient;
@Test
void testHelloQuery() {
String graphQlQuery = "{ hello }";
webTestClient.post().uri("/graphql")
.bodyValue(Map.of("query", graphQlQuery))
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.data.hello").isEqualTo("Hello, GraphQL!");
}
}Runnable: Query & Assert Result
Here's a full runnable example. We have a simple Spring Boot app with a hello GraphQL query, and an integration test verifying its output.
Notice how jsonPath is used to navigate the GraphQL response structure (data.hello) and assert the value.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
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.test.web.reactive.server.WebTestClient;
import java.util.Map;
// --- Application Code ---
@SpringBootApplication
public class GraphQLApp {
public static void main(String[] args) {
SpringApplication.run(GraphQLApp.class, args);
}
}
@Controller
class HelloResolver {
@QueryMapping
public String hello() {
return "Hello, GraphQL!";
}
}
// --- Test Code ---
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class HelloQueryIntegrationTest {
@Autowired
private WebTestClient webTestClient;
@Test
void testHelloQuery() {
String graphQlQuery = "{ hello }";
webTestClient.post().uri("/graphql")
.bodyValue(Map.of("query", graphQlQuery))
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.data.hello").isEqualTo("Hello, GraphQL!");
}
}Testing Queries with Variables
Many GraphQL queries take arguments. You can pass these as variables in your request payload. The variables field in the JSON request body should be a map of variable names to their values.
Remember to define the variables in your GraphQL query string (e.g., query MyQuery($name: String!)).
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.test.web.reactive.server.WebTestClient;
import java.util.Map;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class QueryWithVarsTest {
@Autowired
private WebTestClient webTestClient;
@Test
void testGreetQueryWithName() {
String graphQlQuery = "query Greet($name: String!) { greet(name: $name) }";
Map<String, Object> variables = Map.of("name", "Coddy");
webTestClient.post().uri("/graphql")
.bodyValue(Map.of("query", graphQlQuery, "variables", variables))
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.data.greet").isEqualTo("Hello, Coddy!");
}
}Integration Testing a Mutation
Mutations are used for creating, updating, or deleting data. Testing them follows a similar pattern to queries but you'll use the mutation keyword in your GraphQL string.
It's good practice to assert the return value of the mutation and, if applicable, verify the state change (e.g., by performing a subsequent query).
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.test.web.reactive.server.WebTestClient;
import java.util.Map;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class MutationIntegrationTest {
@Autowired
private WebTestClient webTestClient;
@Test
void testCreateItemMutation() {
String graphQlMutation = "mutation CreateItem($name: String!) { createItem(name: $name) { id name } }";
Map<String, Object> variables = Map.of("name", "New Widget");
webTestClient.post().uri("/graphql")
.bodyValue(Map.of("query", graphQlMutation, "variables", variables))
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.data.createItem.name").isEqualTo("New Widget");
}
}Handling GraphQL Errors in Tests
When your GraphQL API encounters an error (e.g., validation failure, unauthorized access), it typically returns an errors array in the response body, alongside a potential data field (if some parts succeeded).
You can use jsonPath to check for the presence and content of these error messages in your tests.
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.test.web.reactive.server.WebTestClient;
import java.util.Map;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class ErrorHandlingTest {
@Autowired
private WebTestClient webTestClient;
@Test
void testInvalidInputError() {
String graphQlMutation = "mutation CreateItem($name: String!) { createItem(name: $name) { id } }";
Map<String, Object> variables = Map.of("name", ""); // Assume empty name is invalid
webTestClient.post().uri("/graphql")
.bodyValue(Map.of("query", graphQlMutation, "variables", variables))
.exchange()
.expectStatus().isOk() // GraphQL errors usually return 200 OK
.expectBody()
.jsonPath("$.errors").isArray()
.jsonPath("$.errors[0].message").isNotEmpty()
.jsonPath("$.errors[0].message").isEqualTo("Item name cannot be empty.");
}
}Testing Protected Endpoints
If your GraphQL API uses Spring Security, you'll want to test how it responds to authenticated and unauthenticated requests. WebTestClient allows you to easily add headers, including authorization tokens.
This ensures your security configuration correctly protects your GraphQL fields and operations.
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.test.web.reactive.server.WebTestClient;
import java.util.Map;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class ProtectedEndpointTest {
@Autowired
private WebTestClient webTestClient;
@Test
void testProtectedQuery_unauthorized() {
String graphQlQuery = "{ protectedData }";
webTestClient.post().uri("/graphql")
.bodyValue(Map.of("query", graphQlQuery))
.exchange()
.expectStatus().isOk() // GraphQL often returns 200 with errors for auth issues
.expectBody()
.jsonPath("$.errors").isArray()
.jsonPath("$.errors[0].message").isEqualTo("Unauthorized access");
}
@Test
void testProtectedQuery_authorized() {
String graphQlQuery = "{ protectedData }";
String validToken = "mock-jwt-token"; // In a real app, generate a valid test token
webTestClient.post().uri("/graphql")
.header("Authorization", "Bearer " + validToken)
.bodyValue(Map.of("query", graphQlQuery))
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.data.protectedData").isEqualTo("Secret Info");
}
}Quick Check: Integration Tests
Consider the following GraphQL query and a Spring Boot application that exposes a product(id: ID!) query. Which WebTestClient assertion correctly verifies that a product with ID '123' and name 'Laptop' is returned?
Recap: GraphQL Integration Testing
In this lesson, you learned how to perform integration tests for your GraphQL APIs using Spring Boot.
- We covered setting up your test environment with
@SpringBootTestandWebTestClient. - You saw how to craft and execute GraphQL queries and mutations, including passing variables.
- We explored asserting the expected data in the response using
jsonPath. - Finally, you learned to handle error responses and test protected endpoints.
Integration tests are vital for ensuring the robustness and correctness of your GraphQL API!
よくある質問
「GraphQL APIの結合テスト」レッスンは無料ですか?
はい。「GraphQL APIの結合テスト」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、GraphQL APIs with Spring Bootコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 GraphQL APIs with Spring Bootコースには全4レッスンが含まれています。
「GraphQL APIの結合テスト」で何を学びますか?
GraphQL API全体の結合テストを実施し、Query、Mutation、Subscriptionをエンドツーエンドで検証します。 ブラウザで直接実行するハンズオンコードでGraphQL APIs with Spring Bootを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
GraphQL APIs with Spring Bootを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGraphQL APIs with Spring Bootは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「GraphQL APIの結合テスト」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGraphQL APIs with Spring Bootレッスンでコードを書いて実行できますか?
はい。すべてのGraphQL APIs with Spring Bootレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。