Unit-тестирование: тестирование отдельных функций и модулей
Зачем тестировать код? 🤔
Когда пишешь код, кажется, что всё работает идеально. Но стоит изменить пару строк — и в другом месте неожиданно ломается логика. Unit-тесты помогают поймать ошибки до того, как они доберутся до пользователей.
🔍 Что даёт unit-тестирование?
- Быструю проверку работы кода без запуска всего приложения.
- Уверенность в изменениях — если тесты проходят, значит, ничего не сломалось.
- Документирование — тесты показывают, как функция должна работать.
💡 Совет: Тесты — это не трата времени. Они экономят часы на отладке в будущем!
Пишем первый тест 🛠️
Допустим, у нас есть функция, которая складывает два числа:
function sum(a, b) {
return a + b;
}
Проверим её работу с помощью Jest — популярного фреймворка для тестирования.
-
Установка Jest (если ещё не стоит):
bash npm install --save-dev jest -
Тест для
sum():
const sum = require('./sum'); // Импортируем функцию
test('Проверяем, что 1 + 2 равно 3', () => {
expect(sum(1, 2)).toBe(3);
});
🔹 Разберём код:
- test() — создаёт тест-кейс.
- expect() — проверяет, соответствует ли результат ожидаемому.
- toBe() — матчер (проверка на точное равенство).
Запускаем тест:
npx jest
✅ Если всё верно, увидишь зелёный PASS!
Тестируем сложные сценарии 🧩
Функции бывают капризными. Например, вот эта проверяет, является ли строка палиндромом:
function isPalindrome(str) {
if (typeof str !== 'string') return false;
const cleaned = str.toLowerCase().replace(/[^a-z]/g, '');
return cleaned === cleaned.split('').reverse().join('');
}
Пишем тесты для разных случаев:
test('Проверка на палиндром', () => {
expect(isPalindrome('А роза упала на лапу Азора')).toBe(true);
expect(isPalindrome('JavaScript')).toBe(false);
expect(isPalindrome(12321)).toBe(false); // Не строка!
});
💡 Важно: Хороший тест проверяет:
- Ожидаемое поведение (корректные данные).
- Крайние случаи (пустые строки, null, неверные типы).
- Ошибки, которые могут возникнуть.
Mock-функции: тестируем зависимости 🎭
Иногда функция зависит от внешних вызовов (API, база данных). Чтобы не ждать ответа сервера, используем mock — «заглушку».
Допустим, есть функция, которая получает пользователя по API:
async function fetchUser(userId) {
const response = await fetch(`https://api.example.com/users/${userId}`);
return response.json();
}
Тестируем её, подменив реальный fetch:
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ id: 1, name: 'Danila' }),
})
);
test('Получаем пользователя', async () => {
const user = await fetchUser(1);
expect(user).toEqual({ id: 1, name: 'Danila' });
});
🔹 Что произошло?
1. jest.fn() создаёт mock-функцию.
2. Подменяем fetch на нашу заглушку.
3. Проверяем, что функция возвращает нужные данные.
Структура тестов: describe и it 📂
Для удобства тесты группируют в блоки:
describe('Математические функции', () => {
it('Сложение двух чисел', () => {
expect(sum(2, 3)).toBe(5);
});
it('Умножение на ноль', () => {
expect(multiply(5, 0)).toBe(0);
});
});
📌 Почему это полезно?
- Логическая группировка тестов.
- Читаемые отчёты (describe и it выводятся в консоли).
Что дальше? 🚀
- Покрытие кода: Узнай, сколько кода проверено тестами (
jest --coverage). - TDD: Попробуй подход «Сначала тест — потом код».
- Другие фреймворки: Mocha, Chai, Jasmine.
Как говорит Данила Бежин в своих видео: «Тесты — это как страховка для программиста. Лучше иметь и не нуждаться, чем нуждаться и не иметь» 😉
Попробуй написать тест для своей функции прямо сейчас!