Unit-тестирование: тестирование отдельных функций и модулей

Зачем тестировать код? 🤔

Когда пишешь код, кажется, что всё работает идеально. Но стоит изменить пару строк — и в другом месте неожиданно ломается логика. Unit-тесты помогают поймать ошибки до того, как они доберутся до пользователей.

🔍 Что даёт unit-тестирование?
- Быструю проверку работы кода без запуска всего приложения.
- Уверенность в изменениях — если тесты проходят, значит, ничего не сломалось.
- Документирование — тесты показывают, как функция должна работать.

💡 Совет: Тесты — это не трата времени. Они экономят часы на отладке в будущем!


Пишем первый тест 🛠️

Допустим, у нас есть функция, которая складывает два числа:

function sum(a, b) {
  return a + b;
}

Проверим её работу с помощью Jest — популярного фреймворка для тестирования.

  1. Установка Jest (если ещё не стоит):
    bash npm install --save-dev jest

  2. Тест для 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.

Как говорит Данила Бежин в своих видео: «Тесты — это как страховка для программиста. Лучше иметь и не нуждаться, чем нуждаться и не иметь» 😉

Попробуй написать тест для своей функции прямо сейчас!

Скрыть рекламу навсегда

🌱 Индвидидулаьные занятия

Индивидуальные онлайн-занятия по программированию для детей и подростков

Личный подход, без воды, с фокусом на понимание и реальные проекты.

🚀 Записаться на занятие