Testing a GraphQL API is an important part of development — it ensures the schema, queries, mutations, and data safety work correctly. We'll use JUnit and MockMvc — tools that have proven themselves over time for testing Spring applications. The uniqueness of testing GraphQL APIs comes from the need to validate queries similarly to REST, while accounting for GraphQL specifics like selecting only requested fields and handling complex nested structures.
Setting up the test environment for GraphQL
Before starting tests you need to set up the test environment properly. We'll add the required dependencies, configure test data, and prepare MockMvc to work with GraphQL requests.
Add dependencies to pom.xml
Make sure you have the following dependencies included:
<dependencies>
<!-- Dependencies for GraphQL -->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>15.0.0</version>
</dependency>
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>11.1.0</version>
</dependency>
<!-- Testing dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. Test context setup
We use the @SpringBootTest annotation to bring up the application context during tests. Also wire MockMvc to send requests.
@SpringBootTest
@AutoConfigureMockMvc
public class GraphQLTest {
@Autowired
private MockMvc mockMvc;
}
Writing test scenarios
Let's write a few tests for our GraphQL API. We'll test queries, mutations, and error handling.
1. Testing a GraphQL query
Suppose we have a schema schema.graphql:
type Query {
getBook(id: ID!): Book
}
type Book {
id: ID!
title: String
author: String
}
We'll test a query to fetch a book by ID:
query {
getBook(id: "1") {
id
title
author
}
}
Test method for this query:
@Test
void testGetBookQuery() throws Exception {
String query = """
{
"query": "query { getBook(id: \\"1\\") { id title author } }"
}
""";
mockMvc.perform(post("/graphql")
.contentType(MediaType.APPLICATION_JSON)
.content(query))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.getBook.id").value("1"))
.andExpect(jsonPath("$.data.getBook.title").value("GraphQL for Beginners"))
.andExpect(jsonPath("$.data.getBook.author").value("John Doe"));
}
In the code:
- In
querywe build the GraphQL request body in JSON format. - We use MockMvc to send a POST to
/graphql. - We check the response status with
status().isOk(). - We validate the response data using
jsonPath.
2. Testing a mutation
If we have a mutation to add a new book:
mutation {
addBook(input: { title: "Spring Boot with GraphQL", author: "Jane Doe" }) {
id
title
author
}
}
Test method for the mutation:
@Test
void testAddBookMutation() throws Exception {
String mutation = """
{
"query": "mutation { addBook(input: { title: \\"Spring Boot with GraphQL\\", author: \\"Jane Doe\\" }) { id title author } }"
}
""";
mockMvc.perform(post("/graphql")
.contentType(MediaType.APPLICATION_JSON)
.content(mutation))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.addBook.title").value("Spring Boot with GraphQL"))
.andExpect(jsonPath("$.data.addBook.author").value("Jane Doe"));
}
Note that we check the fields the mutation returns. This helps make sure the mutation works correctly.
3. Testing errors
GraphQL APIs often return errors in the errors field. Let's test what happens if the requested book isn't found:
query {
getBook(id: "999") {
id
title
author
}
}
Test method:
@Test
void testGetBookNotFound() throws Exception {
String query = """
{
"query": "query { getBook(id: \\"999\\") { id title author } }"
}
""";
mockMvc.perform(post("/graphql")
.contentType(MediaType.APPLICATION_JSON)
.content(query))
.andExpect(status().isOk())
.andExpect(jsonPath("$.errors").exists())
.andExpect(jsonPath("$.errors[0].message").value("Book not found"));
}
Here we check that the errors field is present and that the error contains the message "Book not found".
Testing complex queries
Complex GraphQL queries can include nested fields and multiple levels of data. For example:
query {
getBook(id: "1") {
id
title
author
reviews {
reviewer
comment
}
}
}
Test this query similarly — validate the nested JSON structures:
@Test
void testGetBookWithReviews() throws Exception {
String query = """
{
"query": "query { getBook(id: \\"1\\") { id title author reviews { reviewer comment } } }"
}
""";
mockMvc.perform(post("/graphql")
.contentType(MediaType.APPLICATION_JSON)
.content(query))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.getBook.reviews[0].reviewer").value("Alice"))
.andExpect(jsonPath("$.data.getBook.reviews[0].comment").value("Great book!"));
}
Testing security
If we have token-based authentication (e.g., JWT), we can add the token to the header:
@Test
void testAuthorizedQuery() throws Exception {
String query = """
{
"query": "query { getBook(id: \\"1\\") { id title author } }"
}
""";
mockMvc.perform(post("/graphql")
.header(HttpHeaders.AUTHORIZATION, "Bearer mock-jwt-token")
.contentType(MediaType.APPLICATION_JSON)
.content(query))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.getBook.title").value("GraphQL for Beginners"));
}
Summary
Testing GraphQL APIs with JUnit and MockMvc is a powerful way to ensure your application's stability and correctness. We covered testing queries, mutations, errors, complex nested structures, and security. These approaches will help you confidently get your app ready for production.
GO TO FULL VERSION