Юнит-тестирование компонентов

Юнит-тестирование в Inferno направлено на проверку отдельных компонентов на корректность работы их логики, рендеринга и взаимодействия с состоянием. Основная цель — выявление ошибок на уровне отдельного блока приложения до интеграции с другими компонентами.

Структура тестов

Каждый тест обычно состоит из трех этапов: подготовка, выполнение и проверка результата.

  1. Подготовка (Arrange) Здесь создаются необходимые данные, свойства (props) и состояние (state) компонента. Для компонентов Inferno это может включать создание mock-функций или начального состояния хранилища.

  2. Выполнение (Act) Выполняются действия, которые нужно протестировать. В Inferno это может быть рендеринг компонента с определенными пропсами, вызов методов компонента или имитация событий, таких как клики или изменения формы.

  3. Проверка (Assert) Сравнивается результат выполнения с ожидаемым поведением. Например, проверка рендера виртуального DOM, состояния компонента после события или вызова функции обратного вызова.

Инструменты для тестирования

Для юнит-тестирования компонентов Inferno чаще всего используются следующие инструменты:

  • Jest — фреймворк для тестирования с возможностью мокирования модулей и функций.
  • Inferno Test Utils — набор вспомогательных функций для рендеринга компонентов и взаимодействия с их деревом.
  • Enzyme (с адаптерами для Inferno) — позволяет производить shallow- и full-render компонентов, проверять их состояние и свойства.

Рендеринг компонентов для теста

Inferno предоставляет функцию render и createVNode, что позволяет создавать виртуальный DOM для тестов:

import { render } from 'inferno';
import { createVNode } from 'inferno-create-element';
import { MyComponent } from './MyComponent';

const container = document.createElement('div');

render(<MyComponent prop1="test" />, container);

expect(container.textContent).toContain('test');

createVNode позволяет создавать виртуальные узлы без полноценного рендеринга, что ускоряет тесты и делает их более изолированными.

Shallow-тестирование

Shallow-тестирование изолирует компонент от его дочерних элементов, позволяя проверить только собственную логику компонента:

import { shallow } from 'inferno-test-utils';
import { MyComponent } from './MyComponent';

const wrapper = shallow(<MyComponent prop1="value" />);
expect(wrapper.find('button').length).toBe(1);

Проверяется наличие элементов, их свойства и базовые события без необходимости рендерить весь поддерево компонентов.

Тестирование событий

Для проверки реакций на пользовательские действия используются имитации событий:

import { render } from 'inferno';
import { MyButton } from './MyButton';

const container = document.createElement('div');
const onClickM ock = jest.fn();

render(<MyButton onCl ick={onClickMock} />, container);

container.querySelector('button').click();
expect(onClickMock).toHaveBeenCalled();

Можно тестировать любые события: click, input, change, keydown, а также вызовы методов жизненного цикла.

Тестирование жизненного цикла

Inferno поддерживает жизненный цикл компонентов, включая методы componentDidMount, componentDidUpdate и componentWillUnmount. Эти методы можно тестировать с использованием мок-функций и проверки состояния после рендеринга:

import { render } from 'inferno';
import { LifecycleComponent } from './LifecycleComponent';

const container = document.createElement('div');
const instance = render(<LifecycleComponent />, container);

expect(instance.state.loaded).toBe(true);

Особое внимание уделяется корректному вызову методов при изменении пропсов и состоянии, чтобы убедиться, что побочные эффекты выполняются правильно.

Мокирование зависимостей

Компоненты часто используют внешние сервисы или контекст. Для юнит-тестов такие зависимости заменяются моками, чтобы тестировать компонент изолированно:

jest.mock('../api', () => ({
  fetchData: jest.fn(() => Promise.resolve({ data: 'mocked' }))
}));

Это позволяет проверять реакцию компонента на различные сценарии без обращения к реальной сети.

Рекомендации по организации тестов

  • Тесты должны быть атомарными — каждый проверяет только один аспект компонента.
  • Использовать отдельные контейнеры для рендеринга, чтобы исключить влияние предыдущих тестов.
  • Проверять как визуальный вывод, так и изменение состояния и вызовы функций.
  • Использовать beforeEach и afterEach для подготовки и очистки окружения тестов.
  • Мокировать сторонние зависимости, чтобы тест оставался быстрым и детерминированным.

Пример комплексного теста

import { render } from 'inferno';
import { MyForm } from './MyForm';

const container = document.createElement('div');
const onSubmitM ock = jest.fn();

render(<MyForm onSub mit={onSubmitMock} />, container);

const input = container.querySelector('input');
input.value = 'Hello';
input.dispatchEvent(new Event('input'));

const form = container.querySelector('form');
form.dispatchEvent(new Event('submit'));

expect(onSubmitMock).toHaveBeenCalledWith({ text: 'Hello' });
expect(container.querySelector('input').value).toBe('');

В этом примере проверяется корректная работа формы: изменение состояния через input, вызов обработчика onSubmit и сброс поля после отправки.

Заключение по методике

Юнит-тестирование компонентов Inferno строится на принципах изоляции, предсказуемости и проверки конкретного поведения. Комбинация рендеринга виртуального DOM, мокирования зависимостей и имитации событий позволяет создавать быстрые и надежные тесты, обеспечивающие стабильность приложения на этапе разработки.