Unit-тестирование
Unit-тестирование помогает стабилизировать процесс разработки при помощи тестов на базовые составляющие кода: функции, методы, классы и целые блоки кода, например:
- Функция вычисления общей стоимости заказа
- Метод сортировки новостей по дате
- Колбек при переходе на страницу
Покрытие unit-тестами позволяет:
- Повысить стабильность рефакторинга
- Уменьшить количество ошибок на ранних стадиях разработки
- Увеличить доверие + получить гарантии работоспособности кода
- Задокументировать код
- Дефекты будут найдены позже, их исправление станет дороже
- Новый код будет лежать «рядом» с исходным, вместо изменений
- Проект быстро устареет и его потребуется переписать с нуля
Unit-тестирование трудоемкий процесс отнимающий значимое количество рабочего времени, поэтому перед тем как начать писать тест следует обдумать что конкретно вы собираетесь покрыть тестом.
Что покрывать unit-тестами?
Вопрос который мучает многих разработчиков, так как возможности Jest в сочетании с другими инструментами позволяют тестировать компоненты на уровне сквозных тестов (e2e).
Концептуально стоит тестировать любой код, отказ которого может привести к потере денег, например:
На прикладном уровне unit-тестами следует тестировать состояние и поведение кода.
Тестирование состояния
Тестируя состояние мы подаем на вход данные и проверяем:
1. Корректность вывода утилитарных функций
function sum(a: number, b: number) :number { return a + b } test("sum of 2 numbers return correct value", () => { const result = sum(1, 2) expect(result).toEqual(3) })
2. Корректность отображения props
глупых компонентов
import { render } from "@testing-library/react"; test("breadcrumbs renders correct count of items", () => { const items = ["Главная", "Категория", "Статья"] const component = render(<Breadcrumbs items={items} visible={2} />) const items = component.querySelector('.items') // позитвные сценарии expect(items).toHaveLength(2) expect(items).toHaveTextContent("Главная") expect(items).toHaveTextContent("Категория") // негативные сценарии expect(items).not.toHaveTextContent("Статья") })
3. Корректность изменения state
глупых компонентов:
import { renderHook, waitFor } from "@testing-library/react"; function useCounter() { const [count, setCount] = useState(0) const increment = () => setCount((x) => x + 1) return { count, increment } } test("useCounter increment method works correct", async () => { const result = renderHook(useCounter) waitFor(() => { result.current.increment() }) expect(result.current.count).toBe(1) })
Тестирование поведения
Тестируя поведение мы совершаем действия и смотрим:
1. Как компонент взаимодействует c другими компонентами
2. Как компонент взаимодействует с пользователем
3. Как компонент реагирует на ответы с сервера
Что такое хороший тест?
- Проверяет только 1 утверждение
- Изолирован от других тестов и окружения
- Выполняться быстро и параллельно
- Соблюдает структуру, конвенцию именования
- Имеет небольшой размер
Пишем тесты с умом
Бездумное написание тестов не помогает, а даже вредит проекту.
Если раньше у вас был один некачественный продукт, то написав тесты, не разобравшись, вы получите — два, и бонусом удвоенное время на сопровождение и поддержку за ваш счёт.
Не стоит относиться к тестам как к второсортному коду.
Многие начинающие разработчики ошибочно полагают, что DRY, KISS и другие подходы, да даже переиспользование переменных для test-id
— это только для кода в продакшен, а в тестах допустимо всё.
Тесты так же являются важным кодом, просто пользователи этого кода — другие разработчики.
Какой процент покрытия?
Добиваться 100% покрытия бессмысленно, так как такой процент покрытия не гарантирует вам безотказную работу вашего приложения.
Хорошие практики
- На баг всегда должен быть написан unit-тест
- Писать unit-тесты на негативные сценарии
- Описывать unit-тест по структуре AAA
- Cтремиться к 80% покрытию
- Завязываться на test-id для обращения к DOM-элементами
Плохие практики
- Unit-тест тестирует смежные модули
- Unit-тест тестирует данные, а не бизнес-логику
- Unit-тест не проверяет исключительные ситуации
- Unit-тест выводит не понятный assertion message
- Unit-тест тестирует компонент UI-библиотеки или готовый пакет
- Стремиться к 100% покрытию
- Завязываться на селекторы и классы для обращения к DOM-элементами