Интеграционное тестирование

Интеграционное тестирование в контексте приложений на Inferno направлено на проверку взаимодействия компонентов между собой и с внешними системами, такими как API, хранилища состояния или маршрутизаторы. В отличие от юнит-тестов, которые изолируют отдельный компонент, интеграционные тесты проверяют, как компоненты работают вместе, обеспечивая корректное поведение всей функциональности.


Настройка окружения для тестирования

Для интеграционного тестирования приложений на Inferno чаще всего используют комбинацию инструментов:

  • Jest — тестовый раннер и фреймворк для ассертов.
  • Inferno Testing Library — библиотека для рендеринга компонентов в тестовой среде и взаимодействия с DOM.
  • jsdom — виртуальное окружение DOM для Node.js, позволяющее тестировать рендеринг компонентов без реального браузера.

Пример базовой конфигурации Jest для Inferno:

module.exports = {
  testEnvironment: "jsdom",
  transform: {
    "^.+\\.jsx?$": "babel-jest",
  },
  setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
};

В jest.setup.js можно подключить необходимые утилиты из @testing-library/inferno.


Рендеринг компонентов

Для интеграционного тестирования ключевой этап — рендеринг компонента с его зависимостями. Inferno Testing Library предоставляет функцию render, которая создаёт виртуальный DOM и позволяет взаимодействовать с компонентом так же, как в браузере.

import { render, fireEvent } from '@testing-library/inferno';
import App from './App';

test('рендеринг и взаимодействие компонентов', () => {
  const { getByText } = render(<App />);
  
  expect(getByText('Загрузить данные')).toBeTruthy();

  fireEvent.click(getByText('Загрузить данные'));

  expect(getByText('Данные загружены')).toBeTruthy();
});

Взаимодействие с состоянием

Inferno использует локальное состояние компонентов и может интегрироваться с глобальными хранилищами вроде Redux или MobX. Интеграционные тесты должны проверять корректность обновления состояния при взаимодействии компонентов.

Пример теста с глобальным хранилищем Redux:

import { render, fireEvent } from '@testing-library/inferno';
import { Provider } from 'inferno-redux';
import configureStore from 'redux-mock-store';
import App from './App';

const mockStore = configureStore([]);
const store = mockStore({ count: 0 });

test('увеличение счётчика', () => {
  const { getByText } = render(
    <Provider store={store}>
      <App />
    </Provider>
  );

  fireEvent.click(getByText('Увеличить'));
  const actions = store.getActions();

  expect(actions).toEqual([{ type: 'INCREMENT' }]);
});

Работа с асинхронными действиями

Асинхронные запросы к серверу или внешним сервисам требуют использования async/await и специальных методов ожидания. Inferno Testing Library предоставляет waitFor для ожидания изменений в DOM после завершения асинхронных операций.

import { render, fireEvent, waitFor } from '@testing-library/inferno';
import App from './App';

test('загрузка данных с API', async () => {
  const { getByText, findByText } = render(<App />);

  fireEvent.click(getByText('Загрузить данные'));

  const result = await findByText('Данные загружены');
  expect(result).toBeTruthy();
});

Тестирование маршрутизации

Inferno Router используется для навигации между страницами. Интеграционные тесты проверяют корректность переходов и отображения компонентов.

import { render } from '@testing-library/inferno';
import { Router, Route, createMemoryHistory } from 'inferno-router';
import App from './App';
import About from './About';

test('переход между страницами', () => {
  const history = createMemoryHistory();
  const { getByText } = render(
    <Router history={history}>
      <Route path="/" component={App} />
      <Route path="/about" component={About} />
    </Router>
  );

  history.push('/about');
  expect(getByText('О нас')).toBeTruthy();
});

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

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

jest.mock('./api', () => ({
  fetchData: jest.fn(() => Promise.resolve({ data: 'Тестовые данные' }))
}));

import { render, waitFor } from '@testing-library/inferno';
import App from './App';
import { fetchData } from './api';

test('отображение мокированных данных', async () => {
  const { getByText } = render(<App />);
  await waitFor(() => expect(getByText('Тестовые данные')).toBeTruthy());
});

Методы проверки и ассерты

Для интеграционных тестов применяются следующие методы проверки:

  • Проверка DOM: getByText, queryByTestId, findByRole.
  • Проверка состояния хранилища: анализ dispatched actions, текущего состояния.
  • Проверка асинхронных операций: waitFor, findBy....
  • Проверка побочных эффектов: вызовы функций, взаимодействие с API, изменение localStorage.

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

  • Каждому компоненту следует выделять отдельный файл тестов.
  • Интеграционные тесты должны охватывать сценарии, включающие несколько компонентов.
  • Асинхронные операции тестировать с использованием async/await и waitFor.
  • Использовать мокирование для внешних сервисов, чтобы тесты были предсказуемыми и изолированными.
  • Разделять тесты по функциональным сценариям: рендеринг, состояние, маршрутизация, взаимодействие с API.