Любой разработчик знает, что чем меньше в API багов, тем меньше звонков в техподдержку. Тестирование — это не просто проверка работоспособности вашей системы, это способ доказать, что она работает так, как задумано. Тестирование GraphQL API особенно важно:
- Проверка логики запросов и мутаций: убедиться, что ваши запросы выполняются корректно, а мутации изменяют данные так, как нужно.
- Обеспечение безопасности: проверить, что пользователи имеют доступ только к тем данным, к которым они должны иметь доступ.
- Производительность: убедиться, что API обрабатывает запросы быстро и эффективно даже под нагрузкой.
- Стабильность: гарантировать, что изменения в коде не ломают уже существующий функционал.
Подходы к тестированию GraphQL API
Как и в любом приложении, тестирование GraphQL API можно разделить на несколько уровней:
Unit-тесты
Это тесты отдельных компонентов приложения, таких как Data Fetchers, Resolvers, или сервисы. Цель — проверить их изолированно от других компонентов.
Пример:
@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. Интеграционные тесты
Здесь мы тестируем взаимодействие между различными компонентами приложения — например, вызов GraphQL-запроса и обработку его Resolver'ом.
Инструменты: Spring Boot Test, MockMvc.
Пример:
@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. Контрактное тестирование
Используется для проверки взаимодействия между микросервисами. Например, если один микросервис предоставляет GraphQL API, а другой к нему обращается, важно убедиться, что договоренности о формате запросов и ответов соблюдаются.
Инструмент: Pact.
4. Нагрузочное тестирование
Позволяет проверить, как API справляется с большим количеством запросов одновременно.
Инструмент: k6.
Использование JUnit для тестирования GraphQL
JUnit — это стандартный фреймворк для тестирования в Java, и он отлично подходит для проверки бизнес-логики GraphQL. Давайте начнем с простого теста Resolver'а.
Пример теста Resolver'а:
@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"));
}
Здесь мы создаем графQL-запрос и проверяем, что данные возвращаются корректно.
Практика: тестирование GraphQL API с использованием JUnit и MockMvc
MockMvc — это мощный инструмент для интеграционного тестирования Spring-приложений, включая GraphQL API.
1. Настройка тестов
Для начала убедитесь, что у вас настроен Spring Boot Test. Для тестирования GraphQL запросов через MockMvc необходимо настроить ваш контроллер.
Пример конфигурации:
@Autowired
private MockMvc mockMvc;
2. Написание тестового сценария
Тестируем запрос на получение пользователя:
@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"));
}
Здесь мы проверяем, что запрос срабатывает и возвращает ожидаемые данные.
Тестирование сложных запросов и мутаций
В более сложных сценариях API может возвращать вложенные объекты или выполнять мутации данных.
Пример сложного запроса:
@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"));
}
Пример мутации:
@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"));
}
Тестирование безопасности и производительности
Проверьте, что пользователи без необходимых прав доступа не могут выполнять определенные запросы.
Пример проверки прав:
@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());
}
Используйте инструменты, такие как k6, для проверки производительности:
k6 run --vus 10 --iterations 100 script.js
Итоги
Теперь у вас есть знания и примеры для написания тестов для GraphQL API. Вы можете проверять как логику отдельных компонентов, так и взаимодействие различных частей системы. Уделяйте особое внимание безопасности и производительности — это ключевые аспекты в реальной разработке.
Все ваши тесты помогут предотвратить баги до того, как они попадут в продакшен. А это значит: спокойный сон и благодарные пользователи!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ