Паттерн Arrange-Act-Assert (AAA) представляет собой структуру для написания тестов, широко используемую при тестировании React-компонентов. Этот подход помогает сделать тесты более читабельными и понятными, улучшая их поддерживаемость и предсказуемость. В контексте использования React Testing Library паттерн помогает разделить процесс тестирования на три логические части, что способствует ясной и последовательной структуре тестов.
На этом этапе происходит подготовка всех зависимостей и начальных условий для выполнения теста. Это может включать создание необходимых данных, настройку моков (mock) для внешних зависимостей, а также рендеринг компонентов с нужными пропсами.
Пример:
import { render, screen } from '@testing-library/react';
import UserProfile from './UserProfile';
test('displays user name correctly', () => {
// Arrange: создание моковых данных для пользователя
const user = { name: 'Иван Иванов', age: 30 };
// Рендерим компонент с использованием подготовленных данных
render(<UserProfile user={user} />);
});
Здесь происходит создание объекта пользователя, который затем
передается в компонент UserProfile. Этап Arrange нацелен на
то, чтобы подготовить все необходимое для проверки функциональности
компонента.
Этот шаг включает в себя выполнение действий, которые нужно
протестировать, такие как клик по кнопке, ввод текста в форму, изменение
состояния и другие взаимодействия с компонентом. В React Testing Library
для этого используются такие методы, как fireEvent и
userEvent, которые имитируют пользовательские
взаимодействия.
Пример:
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';
test('calls onClick when button is clicked', () => {
// Arrange
const handleClick = jest.fn();
render(<Button onCl ick={handleClick}>Click me</Button>);
// Act: имитируем клик по кнопке
fireEvent.click(screen.getByText('Click me'));
// Assert: проверяем, что функция была вызвана
expect(handleClick).toHaveBeenCalledTimes(1);
});
На этапе Act происходит имитация события, в данном случае — клика по кнопке. Важным моментом является то, что действия должны быть максимально приближены к реальному поведению пользователя, что делает тесты более надежными и правдоподобными.
После того как действие выполнено, на этапе Assert необходимо
проверить, что результат тестируемого действия соответствует ожиданиям.
Это может быть проверка изменений в UI, проверка вызова функций,
состояния компонентов и т.д. В React Testing Library для утверждений
часто используются методы типа getByText,
getByRole, queryByText, а также различные
асинхронные методы, такие как findByText.
Пример:
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';
test('button displays "Clicked!" after click', () => {
// Arrange
render(<Button />);
// Act: имитируем клик по кнопке
fireEvent.click(screen.getByText('Click me'));
// Assert: проверяем, что текст изменился
expect(screen.getByText('Clicked!')).toBeInTheDocument();
});
Здесь после клика по кнопке происходит проверка, что текст кнопки изменился на “Clicked!”. Этап Assert позволяет убедиться, что поведение компонента соответствует ожиданиям.
Читаемость Структура Arrange-Act-Assert делает тесты легко читаемыми, так как каждый этап теста имеет свою четкую роль. Это помогает разработчикам быстро ориентироваться в коде тестов и понимать, что именно проверяется.
Меньше дублирования Разделение на этапы помогает избежать дублирования кода, так как каждый из них отвечает за конкретную задачу. Например, если в нескольких тестах требуется один и тот же набор данных, их можно подготовить в разделе Arrange и повторно использовать.
Простота отладки При соблюдении паттерна AAA проще локализовать ошибку в тесте. Если тест не проходит, всегда понятно, на каком из этапов возникла проблема — на этапе подготовки, при выполнении действия или при проверке результата.
Пример полноценного теста с использованием Arrange-Act-Assert паттерна:
import { render, screen, fireEvent } from '@testing-library/react';
import Toggle from './Toggle';
test('toggles visibility of text when button is clicked', () => {
// Arrange: рендерим компонент с начальным состоянием
render(<Toggle />);
// Act: имитируем клик по кнопке
fireEvent.click(screen.getByText('Show/Hide'));
// Assert: проверяем, что текст теперь виден
expect(screen.getByText('Hello, World!')).toBeInTheDocument();
// Act: имитируем второй клик по кнопке
fireEvent.click(screen.getByText('Show/Hide'));
// Assert: проверяем, что текст снова скрыт
expect(screen.queryByText('Hello, World!')).not.toBeInTheDocument();
});
В этом примере паттерн AAA используется для тестирования компонента
Toggle, который меняет видимость текста. Сначала происходит
рендер компонента, затем дважды вызывается клик по кнопке, и на каждом
шаге проверяется правильность изменения состояния видимости текста.
Когда в тестируемом компоненте присутствуют асинхронные операции
(например, запросы к серверу), подход к написанию тестов изменяется, но
паттерн AAA остается актуальным. В таких случаях важно учитывать
задержки в рендеринге или обновлении компонентов, для чего React Testing
Library предоставляет методы findBy и waitFor,
которые позволяют работать с асинхронными задачами.
Пример асинхронного теста:
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import FetchData from './FetchData';
test('displays data after fetching', async () => {
// Arrange
render(<FetchData />);
// Act: имитируем клик для загрузки данных
fireEvent.click(screen.getByText('Load Data'));
// Assert: ожидаем появления текста после асинхронной загрузки
await waitFor(() => screen.getByText('Data Loaded'));
expect(screen.getByText('Data Loaded')).toBeInTheDocument();
});
Здесь используется await waitFor, чтобы дождаться
завершения асинхронного действия и проверки наличия загруженных
данных.
Паттерн Arrange-Act-Assert предоставляет ясную структуру для написания тестов в React, делая их более удобочитаемыми и поддерживаемыми. Разделение теста на три логически связанные части помогает упрощать как написание, так и отладку тестов. Даже при асинхронных операциях этот подход сохраняет свою эффективность, улучшая качество и надежность тестов.