Асинхронное тестирование в Jest требует особого внимания к обработке ошибок, так как многие операции могут завершаться с ошибками. Чтобы правильно протестировать асинхронные функции, необходимо правильно организовать обработку исключений и ошибок в тестах, а также понимать, как Jest работает с асинхронным кодом.
try...catchПри тестировании асинхронного кода, который может выбросить
исключения, следует использовать конструкцию try...catch
для перехвата ошибок. Эта техника подходит для тестов, где ожидается,
что асинхронная операция может завершиться с ошибкой.
Пример использования try...catch в тестах:
test('Асинхронная функция выбрасывает ошибку', async () => {
try {
await someAsyncFunction();
} catch (error) {
expect(error).toBeInstanceOf(Error);
expect(error.message).toBe('Expected error message');
}
});
В данном примере мы ожидаем, что someAsyncFunction()
выбросит ошибку, и с помощью catch перехватываем её. Далее
в блоке catch проверяем тип ошибки и сообщение.
rejects для ожидания ошибокJest предоставляет удобный синтаксис для асинхронных тестов с
ошибками через метод rejects, который позволяет проверить,
что асинхронная функция отклоняет промис с ошибкой.
Пример использования rejects:
test('Асинхронная функция отклоняет промис с ошибкой', async () => {
await expect(someAsyncFunction()).rejects.toThrow('Expected error message');
});
Здесь метод rejects.toThrow() позволяет проверить, что
промис был отклонён и содержал ошибку с ожидаемым сообщением. Это
намного более компактный и читаемый способ, чем использование
try...catch.
Для асинхронных функций, которые возвращают промисы, можно
использовать async/await или метод
then в Jest для корректной обработки ошибок.
Пример с использованием then:
test('Промис отклоняется с ошибкой', () => {
return someAsyncFunction().then(() => {
throw new Error('Expected error');
}).catch((error) => {
expect(error).toBeInstanceOf(Error);
expect(error.message).toBe('Expected error');
});
});
Здесь важно правильно обрабатывать как успешное завершение промиса,
так и отклонение. В случае отклонения промиса выполнение переходит в
блок catch, где ошибка проверяется через
expect.
В случае использования асинхронных операций, использующих колбэки,
например, в старых API или при работе с внешними библиотеками, можно
проверить ошибки с помощью done().
Пример с колбэком:
test('Колбэк вызывает ошибку', (done) => {
someAsyncFunctionWithCallback((error, result) => {
expect(error).toBeInstanceOf(Error);
expect(error.message).toBe('Expected callback error');
done();
});
});
Здесь важно использовать функцию done(), чтобы Jest
знал, что тест завершится только после выполнения колбэка. Это помогает
корректно ожидать асинхронные операции.
Для асинхронных операций, которые могут зависать или выполняться слишком долго, следует использовать тайм-ауты. Jest позволяет установить тайм-аут для теста, что помогает избежать “зависших” тестов.
Пример с установкой тайм-аута:
test('Асинхронная операция с тайм-аутом', async () => {
jest.setTimeout(10000); // Устанавливаем тайм-аут в 10 секунд
await expect(someAsyncFunction()).rejects.toThrow('Timeout error');
});
В этом примере установлено ограничение на время выполнения теста. Если операция не завершится в указанное время, тест будет провален.
async и await в
цепочкахJest также позволяет проверять ошибки в цепочках асинхронных операций. Это часто используется для проверки многократных асинхронных действий, которые могут вызывать ошибки на разных этапах выполнения.
Пример:
test('Цепочка асинхронных операций с ошибкой', async () => {
await expect(
someAsyncFunction()
.then(result => anotherAsyncFunction(result))
.catch(error => {
throw new Error('Chain error');
})
).rejects.toThrow('Chain error');
});
Здесь ошибка может возникнуть как в первом, так и во втором
асинхронном действии. Метод catch используется для
перехвата и повторного выбрасывания ошибки, которая затем проверяется с
помощью rejects.toThrow().
beforeEach и afterEach для подготовки и
очистки ошибокИногда перед выполнением теста нужно подготовить определённое
состояние системы или перехватить глобальные ошибки. Это можно сделать
через хук beforeEach или afterEach. Эти хуки
позволяют организовать настройку теста и его очистку.
Пример использования хука для перехвата ошибок:
beforeEach(() => {
global.console.error = jest.fn(); // Перехватываем вызовы console.error
});
test('Проверка ошибки с перехватом вывода', async () => {
await someAsyncFunctionThatLogsError();
expect(console.error).toHaveBeenCalledWith('Expected error message');
});
В этом примере мы используем хук beforeEach для
перехвата ошибок, выводимых через console.error. После
этого проверяется, был ли вызов с ожидаемым сообщением.
В некоторых случаях необходимо проверять кастомные ошибки, которые могут быть выброшены определённой функцией. Для этого часто используется проверка на конкретные типы ошибок и их сообщения.
Пример:
class CustomError extends Error {
constructor(message) {
super(message);
this.name = 'CustomError';
}
}
test('Проверка кастомной ошибки', async () => {
try {
await someAsyncFunctionThatThrowsCustomError();
} catch (error) {
expect(error).toBeInstanceOf(CustomError);
expect(error.message).toBe('This is a custom error');
}
});
Здесь создаётся класс ошибки CustomError, который потом
проверяется в тесте. Это позволяет тестировать специфичные исключения,
которые могут быть выброшены в процессе работы приложения.
Обработка ошибок в асинхронных тестах является важной частью
тестирования. Jest предоставляет различные способы для работы с
ошибками: использование try...catch, rejects,
done(), настройка тайм-аутов и проверка кастомных ошибок.
Правильное использование этих инструментов позволяет повысить надёжность
тестов и обеспечивать корректное поведение приложения в случае
возникновения ошибок.