GraphQL — это мощный инструмент для построения API, который позволяет клиентам точно запрашивать те данные, которые им нужны, и ничего лишнего. Важно тестировать такие API, чтобы убедиться, что они работают корректно, а также минимизировать вероятность появления ошибок при их изменении. Jest, популярный фреймворк для тестирования JavaScript, предоставляет отличные возможности для тестирования серверов, реализующих GraphQL.
При тестировании GraphQL важно учитывать как тестирование запросов и мутаций, так и проверку обработки ошибок, производительности и интеграцию с базой данных или другими внешними сервисами. Jest предоставляет удобные инструменты для написания юнит-тестов, мокирования зависимостей и проверки поведения серверов.
Для начала необходимо установить все необходимые зависимости. Для тестирования GraphQL с Jest потребуется несколько библиотек:
jest — для тестирования.graphql — для работы с GraphQL.apollo-server или express-graphql — для
создания серверов GraphQL.@testing-library/jest-dom — для улучшенного
тестирования DOM (если тестируется фронтенд).jest-mock — для мокирования функций.Пример установки зависимостей:
npm install jest graphql apollo-server
Настройка тестовой среды для сервера GraphQL может быть выполнена с
использованием специальных утилит для тестирования, таких как
apollo-server-testing, которая предоставляет метод
createTestClient для тестирования GraphQL-запросов.
npm install @apollo/server-testing
Для юнит-тестирования GraphQL-сервера необходимо замокировать зависимости, которые он использует. Важно разделить тесты на два типа: тестирование непосредственно запросов и тестирование функций, которые взаимодействуют с базой данных или внешними сервисами.
Для мокирования запросов можно использовать функцию
jest.fn(), которая позволяет подменить реальную функцию на
фиктивную. Это особенно полезно при тестировании мутаций и обработчиков
запросов, которые обращаются к базе данных.
const mockData = { id: 1, name: 'Test User' };
jest.mock('../resolvers/userResolver', () => ({
getUser: jest.fn(() => mockData)
}));
Для тестирования запросов и мутаций необходимо использовать методы
для отправки запросов на сервер GraphQL. Это можно сделать с помощью
graphql-request или встроенной функции из
apollo-server-testing.
Пример теста для GraphQL-запроса:
import { createTestClient } from '@apollo/server-testing';
import { ApolloServer, gql } from 'apollo-server';
import { typeDefs, resolvers } from '../schema';
const GET_USER_QUERY = gql`
query getUser($id: ID!) {
user(id: $id) {
id
name
}
}
`;
describe('GraphQL Queries', () => {
let server;
let testClient;
beforeAll(() => {
server = new ApolloServer({ typeDefs, resolvers });
testClient = createTestClient(server);
});
it('fetches user by ID', async () => {
const { data } = await testClient.query({
query: GET_USER_QUERY,
variables: { id: 1 },
});
expect(data.user).toEqual({
id: '1',
name: 'Test User',
});
});
});
В этом примере используется метод createTestClient,
который создаёт тестовый клиент для отправки запросов на сервер. Это
позволяет изолировать тесты от реальной базы данных и мокировать только
необходимые данные.
Мутации могут быть протестированы аналогичным образом. Важно убедиться, что мутация корректно изменяет состояние сервера и возвращает правильный ответ.
Пример теста для GraphQL-мутации:
const CREATE_USER_MUTATION = gql`
mutation createUser($name: String!) {
createUser(name: $name) {
id
name
}
}
`;
describe('GraphQL Mutations', () => {
it('creates a new user', async () => {
const { data } = await testClient.mutate({
mutation: CREATE_USER_MUTATION,
variables: { name: 'New User' },
});
expect(data.createUser).toHaveProperty('id');
expect(data.createUser.name).toBe('New User');
});
});
Здесь проверяется, что мутация создает нового пользователя и возвращает правильные данные, включая ID нового пользователя.
Тестирование обработки ошибок — неотъемлемая часть работы с GraphQL. Необходимо проверять, что сервер корректно обрабатывает некорректные запросы, возвращает нужные коды ошибок и сообщения.
Пример теста для ошибок:
const GET_INVALID_USER_QUERY = gql`
query getUser($id: ID!) {
user(id: $id) {
id
name
}
}
`;
describe('GraphQL Error Handling', () => {
it('returns an error for invalid query', async () => {
const { errors } = await testClient.query({
query: GET_INVALID_USER_QUERY,
variables: { id: 'invalid' },
});
expect(errors).toHaveLength(1);
expect(errors[0].message).toBe('User not found');
});
});
Здесь проверяется, что при запросе пользователя с неверным ID сервер корректно возвращает ошибку.
Интеграционные тесты позволяют проверить работу всего сервера GraphQL с реальными базами данных или внешними сервисами. При интеграционном тестировании важно проверять не только логику запросов и мутаций, но и корректность работы всех зависимостей.
Интеграционные тесты могут выглядеть как обычные запросы, но они направлены на проверку взаимодействия различных компонентов системы.
Пример интеграционного теста с базой данных:
import { connectToDatabase, disconnectFromDatabase } from '../db';
beforeAll(async () => {
await connectToDatabase();
});
afterAll(async () => {
await disconnectFromDatabase();
});
it('fetches user from the database', async () => {
const { data } = await testClient.query({
query: GET_USER_QUERY,
variables: { id: 1 },
});
expect(data.user).toHaveProperty('id', '1');
});
В этом примере выполняется подключение к базе данных перед тестами и её отключение после них.
Если сервер GraphQL взаимодействует с внешними API, например, через
REST-запросы, то такие вызовы также следует замокировать. Для этого
можно использовать библиотеки вроде nock или
jest.mock() для подмены HTTP-запросов.
Пример мокирования HTTP-запроса:
import nock from 'nock';
beforeAll(() => {
nock('https://api.example.com')
.get('/user/1')
.reply(200, { id: 1, name: 'Test User' });
});
it('fetches external data for user', async () => {
const { data } = await testClient.query({
query: GET_USER_QUERY,
variables: { id: 1 },
});
expect(data.user).toEqual({
id: '1',
name: 'Test User',
});
});
Здесь используется библиотека nock для замокирования
запросов к внешнему API и возвращения фиктивных данных.
Для удобства можно создавать вспомогательные функции, которые будут использоваться в разных тестах. Например, если несколько тестов выполняют одинаковые запросы, можно вынести их в отдельные переменные или функции для упрощения кода.
Пример использования вспомогательных функций:
const createUser = (name) => {
return testClient.mutate({
mutation: CREATE_USER_MUTATION,
variables: { name },
});
};
it('creates a user with a short name', async () => {
const { data } = await createUser('Short');
expect(data.createUser.name).toBe('Short');
});
Это помогает сделать код более читаемым и удобным для тестирования.
Тестирование GraphQL API с использованием Jest позволяет значительно повысить качество кода и уверенность в его стабильности. Создание эффективных юнит- и интеграционных тестов помогает обнаружить ошибки на ранних этапах разработки, а также обеспечивает легкость в обслуживании и изменении системы в будущем.