Расскажи про стандартные сценарии тестирования Unit тестами
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Стандартные сценарии тестирования Unit тестами
Unit-тестирование — это фундаментальная практика разработки программного обеспечения, направленная на проверку корректности отдельных изолированных модулей (функций, классов, методов) приложения. Цель — убедиться, что каждая "единица" кода ведёт себя ожидаемо в различных условиях. Стандартные сценарии можно разделить на несколько ключевых категорий.
1. Тестирование базовой функциональности (Happy Path)
Проверка, что модуль корректно выполняет свою основную задачу при валидных входных данных. Это первоочерёдной и обязательный сценарий.
Пример на JavaScript (Jest):
// Функция для тестирования
function sum(a, b) {
return a + b;
}
// Unit-тест
test('should return sum of two numbers', () => {
expect(sum(2, 3)).toBe(5);
expect(sum(-1, 1)).toBe(0);
});
2. Тестирование граничных условий (Boundary Testing)
Анализ поведения на краях допустимых диапазонов. Часто ошибки возникают именно здесь.
- Минимальные и максимальные значения: пустые строки, нули, максимальные числа (e.g.,
Number.MAX_SAFE_INTEGER). - Крайние индексы массива: первый (
0) и последний (array.length — 1) элементы. - Пограничные состояния: переход через ноль, работа с
nullилиundefined.
Пример:
function getFirstElement(array) {
if (!Array.isArray(array) || array.length === 0) {
throw new Error('Invalid or empty array');
}
return array[0];
}
test('handles boundary conditions for array', () => {
expect(() => getFirstElement([])).toThrow('Invalid or empty array');
expect(getFirstElement([42])).toBe(42);
expect(getFirstElement([1, 2, 3])).toBe(1);
});
3. Тестирование негативных сценариев (Error Path)
Проверка, что код корректно обрабатывает ошибочные или невалидные входные данные: выбрасывает исключения, возвращает коды ошибок или значения по умолчанию.
- Неверный тип данных (строка вместо числа).
nullилиundefinedаргументы.- Некорректный формат данных (не JSON строка).
- Нарушение предусловий (деление на ноль).
Пример:
function divide(a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
throw new TypeError('Arguments must be numbers');
}
if (b === 0) {
throw new RangeError('Division by zero');
}
return a / b;
}
test('throws errors on invalid input', () => {
expect(() => divide('10', 2)).toThrow(TypeError);
expect(() => divide(10, 0)).toThrow(RangeError);
});
4. Тестирование асинхронного кода
Проверка функций, возвращающих Promise или использующих async/await. Важно убедиться, что тест дожидается завершения асинхронной операции.
Пример:
async function fetchUserData(userId) {
// Имитация асинхронного запроса
const response = await Promise.resolve({ id: userId, name: 'John' });
return response.name;
}
test('resolves with user name', async () => {
await expect(fetchUserData(1)).resolves.toBe('John');
});
5. Тестирование с использованием моков (Mocking)
Для изоляции тестируемого модуля от его зависимостей (внешние API, базы данных, файловая система) используются моки, стабы или шпионы. Это позволяет:
- Контролировать возвращаемые значения зависимостей.
- Проверять, были ли вызваны зависимости с правильными аргументами.
- Имитировать ошибки и исключительные ситуации.
Пример мокинга модуля с помощью Jest:
// users.js
export async function getUserFromAPI(id) {
// Реальный HTTP-вызов
}
// userProcessor.js
import { getUserFromAPI } from './users';
export async function processUser(id) {
const user = await getUserFromAPI(id);
return `User: ${user.name}`;
}
// userProcessor.test.js
import { processUser } from './userProcessor';
import { getUserFromAPI } from './users';
jest.mock('./users');
test('processUser formats name correctly', async () => {
// Мокируем зависимость
getUserFromAPI.mockResolvedValue({ id: 1, name: 'Alice' });
const result = await processUser(1);
expect(result).toBe('User: Alice');
expect(getUserFromAPI).toHaveBeenCalledWith(1); // Проверка вызова
});
6. Тестирование состояния и поведения
- Состояние (State-based): Проверка, что после выполнения метода объект перешёл в ожидаемое состояние (значения полей изменились корректно).
- Поведение (Behavior-based): Проверка взаимодействия между объектами — какие методы были вызваны, с какими параметрами и сколько раз. Используется при тестировании с моками.
Ключевые принципы хороших юнит-тестов (FIRST)
- Fast: Должны выполняться быстро.
- Isolated: Тестируют одну функциональность, изолированы от окружения и других тестов.
- Repeatable: Результат детерминирован и не зависит от внешних факторов.
- Self-validating: Тест сам определяет успех/провал (assertions).
- Timely (или Thorough): Пишутся своевременно (часто до кода — TDD) и покрывают ключевые сценарии.
Следование этим стандартным сценариям позволяет создать надёжный и поддерживаемый тестовый гарнитур, который не только ловит регрессии, но и служит живой документацией к коду и облегчает его рефакторинг.