Тестирование GraphQL API является важным этапом разработки, оно обеспечивает корректность работы схем, запросов, мутаций и безопасность данных. Мы будем использовать JUnit и MockMvc — инструменты, которые уже давно зарекомендовали себя при тестировании Spring приложений. Уникальность тестирования GraphQL API заключается в необходимости проверки запросов подобно REST, но с учетом особенностей GraphQL, таких как выборка только запрашиваемых полей и сложные вложенные структуры.
Настройка тестового окружения для GraphQL
Перед началом тестирования необходимо правильно настроить тестовую среду. Мы добавим все нужные зависимости, настроим тестовые данные и подготовим MockMvc для работы с GraphQL запросами.
Добавляем зависимости в pom.xml
Убедитесь, что у вас подключены следующие зависимости:
<dependencies>
<!-- Зависимости для 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>
<!-- Зависимости для тестирования -->
<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. Настройка тестового контекста
Используем аннотацию @SpringBootTest, чтобы поднять контекст приложения во время тестов. Кроме того, подключим MockMvc для отправки запросов.
@SpringBootTest
@AutoConfigureMockMvc
public class GraphQLTest {
@Autowired
private MockMvc mockMvc;
}
Написание тестовых сценариев
Давайте напишем несколько тестов для проверки нашего GraphQL API. Мы будем тестировать запросы, мутации и обработку ошибок.
1. Тестирование GraphQL запроса
Предположим, у нас есть схема schema.graphql:
type Query {
getBook(id: ID!): Book
}
type Book {
id: ID!
title: String
author: String
}
Мы тестируем запрос, чтобы получить книгу по ID:
query {
getBook(id: "1") {
id
title
author
}
}
Тестовый метод для этого запроса:
@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"));
}
В коде:
- В
queryмы формируем тело GraphQL запроса в формате JSON. - Используем MockMvc для отправки POST-запроса на
/graphql. - Проверяем статус ответа с помощью
status().isOk(). - Проверяем данные ответа через
jsonPath.
2. Тестирование мутации
Если у нас есть мутация для добавления новой книги:
mutation {
addBook(input: { title: "Spring Boot with GraphQL", author: "Jane Doe" }) {
id
title
author
}
}
Тестовый метод для мутации:
@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"));
}
Обратите внимание, что проверяем поля, которые возвращает мутация. Это помогает убедиться, что мутация работает корректно.
3. Тестирование ошибок
GraphQL API часто возвращает ошибки в поле errors. Давайте протестируем, что произойдет, если запрашиваемая книга не найдена:
query {
getBook(id: "999") {
id
title
author
}
}
Тестовый метод:
@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"));
}
Здесь мы проверяем, что поле errors присутствует, и ошибка содержит сообщение "Book not found".
Тестирование сложных запросов
Сложные GraphQL-запросы могут включать вложенные поля и несколько уровней данных. Например:
query {
getBook(id: "1") {
id
title
author
reviews {
reviewer
comment
}
}
}
Тестируем этот запрос аналогично — проверяем вложенные структуры JSON:
@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!"));
}
Тестирование безопасности
Если у нас есть аутентификация через токен (например, JWT), мы можем добавить токен в заголовок:
@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"));
}
Резюме
Тестирование GraphQL API с использованием JUnit и MockMvc — это мощный способ обеспечить стабильность и корректность вашего приложения. Мы рассмотрели тестирование запросов, мутаций, ошибок, сложных вложенных структур и безопасности. Эти подходы помогут вам уверенно готовить приложение к продакшену.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ