Any developer knows that the fewer bugs in an API, the fewer support calls you'll get. Testing isn't just checking that your system works — it's how you prove it works the way it's supposed to. Testing a GraphQL API is especially important:
- Verify query and mutation logic: make sure your queries execute correctly and mutations change data the way they should.
- Ensure security: check that users can only access the data they're supposed to.
- Performance: make sure the API handles requests quickly and efficiently even under load.
- Stability: ensure that code changes don't break existing functionality.
Approaches to testing GraphQL API
Like any application, testing a GraphQL API can be split into several levels:
Unit tests
These are tests for individual components of the app, such as Data Fetchers, Resolvers, or services. The goal is to test them in isolation from other components.
Example:
@Test
void testFetchUserById() {
// Given
UUID userId = UUID.randomUUID();
User mockUser = new User(userId, "John", "Doe");
when(userRepository.findById(userId)).thenReturn(Optional.of(mockUser));
// When
User result = userService.fetchUserById(userId);
// Then
assertEquals(mockUser, result);
}
2. Integration tests
Here we test the interaction between different parts of the app — for example, calling a GraphQL query and having it handled by its Resolver.
Tools: Spring Boot Test, MockMvc.
Example:
@Test
void testGraphQLQuery() throws Exception {
String query = "{ user(id: \"1\") { firstName lastName } }";
mockMvc.perform(post("/graphql")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"query\":\"" + query + "\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.user.firstName").value("John"))
.andExpect(jsonPath("$.data.user.lastName").value("Doe"));
}
3. Contract testing
Used to verify interactions between microservices. For example, if one microservice provides a GraphQL API and another consumes it, it's important to ensure agreements about request and response formats are respected.
Tool: Pact.
4. Load testing
This lets you check how the API handles a large number of simultaneous requests.
Tool: k6.
Using JUnit to test GraphQL
JUnit is the standard testing framework in Java, and it's great for verifying GraphQL business logic. Let's start with a simple Resolver test.
Example Resolver test:
@Test
void testResolveQuery() {
// Given
String query = "{ user(id: \"1\") { firstName, lastName } }";
ExecutionInput executionInput = ExecutionInput.newExecutionInput()
.query(query)
.build();
// When
ExecutionResult executionResult = graphQL.execute(executionInput);
// Then
Map<String, Object7>) data.get("user")).get("firstName"));
}
Here we create a GraphQL query and check that the data comes back correctly.
Practice: testing GraphQL API with JUnit and MockMvc
MockMvc is a powerful tool for integration testing Spring apps, including GraphQL APIs.
1. Setting up tests
First, make sure you have Spring Boot Test configured. To test GraphQL requests via MockMvc you need to set up your controller.
Example configuration:
@Autowired
private MockMvc mockMvc;
2. Writing a test scenario
Testing a query to get a user:
@Test
void testUserQuery() throws Exception {
String query = "{ user(id: \"1\") { firstName, lastName } }";
mockMvc.perform(post("/graphql")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"query\":\"" + query + "\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.user.firstName").value("John"))
.andExpect(jsonPath("$.data.user.lastName").value("Doe"));
}
Here we check that the request works and returns the expected data.
Testing complex queries and mutations
In more complex scenarios the API may return nested objects or perform data mutations.
Example complex query:
@Test
void testComplexQuery() throws Exception {
String query = "{ user(id: \"1\") { firstName, posts { title, content } } }";
mockMvc.perform(post("/graphql")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"query\":\"" + query + "\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.user.firstName").value("John"))
.andExpect(jsonPath("$.data.user.posts[0].title").value("Post 1"))
.andExpect(jsonPath("$.data.user.posts[0].content").value("Content 1"));
}
Example mutation:
@Test
void testCreateUserMutation() throws Exception {
String mutation = "mutation { createUser(input: { firstName: \"Jane\", lastName: \"Doe\" }) { id, firstName, lastName } }";
mockMvc.perform(post("/graphql")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"query\":\"" + mutation + "\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.createUser.firstName").value("Jane"))
.andExpect(jsonPath("$.data.createUser.lastName").value("Doe"));
}
Testing security and performance
Check that users without the necessary permissions can't execute certain requests.
Example permission check:
@Test
@WithMockUser(roles = "ADMIN")
void testAdminAccess() throws Exception {
String query = "{ adminData { sensitiveInfo } }";
mockMvc.perform(post("/graphql")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"query\":\"" + query + "\"}"))
.andExpect(status().isOk());
}
@Test
@WithMockUser(roles = "USER")
void testUnauthorizedAccess() throws Exception {
String query = "{ adminData { sensitiveInfo } }";
mockMvc.perform(post("/graphql")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"query\":\"" + query + "\"}"))
.andExpect(status().isForbidden());
}
Use tools like k6 to check performance:
k6 run --vus 10 --iterations 100 script.js
Conclusion
Now you've got the knowledge and examples to write tests for a GraphQL API. You can verify both the logic of individual components and the interactions between different parts of the system. Pay special attention to security and performance — those are key aspects in real-world development.
All your tests will help catch bugs before they hit production. That means: peaceful sleep and grateful users!
GO TO FULL VERSION