Files
frontend-docs/docs/testing/02-fronend-test.md

343 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
sidebar_position: 2
---
# Типы тестов в приложениях React
Тестирование в приложениях React можно разделить на три основных типа: **модульные тесты**, **интеграционные тесты** и **комплексные (E2E) тесты**. Модульные тесты фокусируются на отдельных компонентах, обеспечивая их корректную работу в изоляции, проверяя такие аспекты, как рендеринг, изменения состояния и обработка событий. Интеграционные тесты проверяют, как компоненты взаимодействуют друг с другом, проверяя поток данных и взаимодействие между различными частями приложения. С другой стороны, тесты E2E моделируют реальные пользовательские сценарии для тестирования всего стека приложений, от пользовательского интерфейса до внутренних служб, гарантируя, что приложение работает так, как задумано с точки зрения пользователя. Каждый тип тестирования играет решающую роль в поддержании надежности приложений React.
## Модульное тестирование
Модульное тестирование включает в себя проверку отдельных компонентов или блоков кода, чтобы убедиться, что они корректно функционируют изолированно. Основная цель проверить, что каждый компонент работает должным образом в различных условиях. В React модульные тесты обычно фокусируются на тестировании отдельных компонентов и их логики без привлечения внешних зависимостей.
### Что тестировать в компонентах React
При модульном тестировании компонентов React учитывайте следующие аспекты:
- **Рендеринг компонентов:** Убедитесь, что компонент корректно отрисовывается с использованием различных реквизитов.
- **Обработка событий:** Проверьте, работают ли обработчики событий (например, onClick, onChange) должным образом.
- **Изменения состояния:** Убедитесь, что переходы между состояниями происходят корректно в зависимости от взаимодействия с пользователем или изменений в prop.
- **Вывод:** Проверьте корректность вывода компонента (например, отображаемого HTML-кода).
### Примеры модульных тестов в React
Рассмотрим простой компонент React, кнопку, которая меняет свою метку при нажатии:
```jsx
// Button.js
import React, { useState } from 'react';
function Button() {
const [label, setLabel] = useState('Click me');
return (
<button onClick={() => setLabel('Clicked')}>
{label}
</button>
);
}
export default Button;
```
Модульный тест для этого компонента с использованием библиотеки тестирования Jest и React может выглядеть следующим образом:
```jsx
// Button.test.js
import { render, fireEvent } from '@testing-library/react';
import Button from './Button';
test('Button changes label when clicked', () => {
const { getByText } = render(<Button />);
const buttonElement = getByText('Click me');
fireEvent.click(buttonElement);
expect(buttonElement.textContent).toBe('Clicked');
});
```
## Интеграционное тестирование
**Интеграционное тестирование** изучает, как различные части системы работают вместе. В контексте приложений React оно включает в себя тестирование взаимодействия между компонентами, гарантируя правильную интеграцию и бесперебойную передачу данных через приложение.
### Когда использовать интеграционные тесты
Интеграционные тесты подходят, когда:
- **Взаимодействие нескольких компонентов:** обеспечение надлежащей совместной работы компонентов.
- **Потоки данных проходят через несколько уровней:** проверка распространения данных и управление состоянием.
- **Сложные взаимодействия с пользователем:** тестирование последовательности действий пользователя, в которых задействовано несколько компонентов.
### Примеры интеграционных тестов в React
Рассмотрим приложение с компонентом профиля пользователя, который извлекает и отображает пользовательские данные:
```jsx
// UserProfile.js
import React, { useEffect, useState } from 'react';
import axios from 'axios';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
axios.get(`/api/users/${userId}`).then(response => {
setUser(response.data);
});
}, [userId]);
if (!user) return <div>Loading...</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
export default UserProfile;
```
Интеграционный тест может выглядеть следующим образом:
```jsx
// UserProfile.test.js
import { render, screen, waitFor } from '@testing-library/react';
import axios from 'axios';
import UserProfile from './UserProfile';
jest.mock('axios');
test('fetches and displays user data', async () => {
const user = { name: 'John Doe', email: 'john.doe@example.com' };
axios.get.mockResolvedValue({ data: user });
render(<UserProfile userId="123" />);
expect(screen.getByText('Loading...')).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('john.doe@example.com')).toBeInTheDocument();
});
});
```
## Комплексное тестирование (E2E)
**Комплексное тестирование (E2E)** включает в себя тестирование всего приложения с точки зрения пользователя. Оно имитирует реальные сценарии взаимодействия пользователя с приложением через пользовательский интерфейс, чтобы гарантировать корректное поведение системы в целом. Тесты E2E имеют решающее значение для проверки корректности работы приложения в среде, подобной производственной.
### Отличия от модульных и интеграционных тестов
В то время как модульные тесты фокусируются на отдельных компонентах, а интеграционные на взаимодействии между компонентами, тесты E2E охватывают весь стек приложений. Они тестируют пользовательский интерфейс, серверные службы и все, что находится между ними, чтобы убедиться, что приложение обеспечивает ожидаемую функциональность для конечного пользователя.
### Примеры E2E-тестов в React
Рассмотрим простой процесс входа в систему в приложении React:
```jsx
// LoginPage.js
import React, { useState } from 'react';
function LoginPage() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleLogin = () => {
// Perform login logic here
};
return (
<div>
<input
type="text"
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button onClick={handleLogin}>Login</button>
</div>
);
}
export default LoginPage;
```
Тест E2E с использованием Cypress может выглядеть следующим образом:
```jsx
// login.spec.js
describe('Login Flow', () => {
it('allows a user to log in', () => {
cy.visit('/login');
cy.get('input[placeholder="Username"]').type('testuser');
cy.get('input[placeholder="Password"]').type('password123');
cy.get('button').contains('Login').click();
// Assert the expected behavior after login
cy.url().should('include', '/dashboard');
cy.contains('Welcome, testuser').should('be.visible');
});
});
```
Понимание различных типов тестов — модульных, интеграционных и сквозных — имеет решающее значение для обеспечения надежности приложений React. Модульные тесты фокусируются на отдельных компонентах, интеграционные тесты проверяют взаимодействие между компонентами, а тесты E2E моделируют реальные пользовательские сценарии для тестирования всего стека приложений.
## Рекомендации по тестированию приложений React
Тестирование имеет решающее значение для поддержания качества и надежности приложений React. Соблюдение рекомендаций гарантирует эффективность и ремонтопригодность тестов. Здесь мы расскажем о нескольких ключевых рекомендациях по тестированию приложений React.
### Прежде чем исправлять ошибки, напишите тесты
Написание тестов перед исправлением ошибок гарантирует, что ошибка будет хорошо понята и что исправление действительно решит проблему. Эта практика, известная как регрессионное тестирование, помогает предотвратить повторение одной и той же ошибки. Например, если предполагается, что кнопка обновляет состояние, но не может этого сделать, написание теста на ожидаемое поведение перед его исправлением гарантирует, что решение будет проверено.
```jsx
// Example of a regression test
test('button updates state when clicked', () => {
const { getByText } = render(<Button />);
const buttonElement = getByText('Click me');
fireEvent.click(buttonElement);
expect(buttonElement.textContent).toBe('Clicked');
});
```
### Тестируйте поведение компонента, а не его реализацию
Тестирование поведения, а не реализации компонентов гарантирует устойчивость тестов к рефакторингу. Тесты должны быть сосредоточены на входных и выходных данных компонента, а не на его внутренних деталях. Например, тестирование отображаемых выходных данных на основе реквизитов и изменений состояния предпочтительнее тестирования конкретных функций или методов, используемых в компоненте.
```jsx
// Example of testing behavior
test('renders correct label based on prop', () => {
const { getByText } = render(<LabelComponent label="Test Label" />);
expect(getByText('Test Label')).toBeInTheDocument();
});
```
### Используйте поверхностный рендеринг для модульных тестов
Поверхностный рендеринг полезен для изолированного тестирования отдельных компонентов без рендеринга дочерних компонентов. Это ускоряет и упрощает понимание модульных тестов. Поверхностный рендеринг можно выполнить с помощью таких библиотек, как Enzyme.
```jsx
// Example of shallow rendering with Enzyme
import { shallow } from 'enzyme';
import Button from './Button';
test('Button renders correctly', () => {
const wrapper = shallow(<Button />);
expect(wrapper.text()).toBe('Click me');
});
```
### Имитация внешних зависимостей
Имитация внешних зависимостей, таких как API или сторонние сервисы, помогает изолировать тестируемый компонент и обеспечивает согласованное выполнение тестов. Библиотеки, подобные Jest, предоставляют надежные возможности для имитационного моделирования.
```jsx
// Example of mocking an API call with Jest
import axios from 'axios';
import UserProfile from './UserProfile';
jest.mock('axios');
test('fetches and displays user data', async () => {
const user = { name: 'John Doe', email: 'john.doe@example.com' };
axios.get.mockResolvedValue({ data: user });
const { findByText } = render(<UserProfile userId="123" />);
expect(await findByText('John Doe')).toBeInTheDocument();
expect(await findByText('john.doe@example.com')).toBeInTheDocument();
});
```
### Выполняйте тесты быстро и надежно
Быстрые и надежные тесты обеспечивают быструю обратную связь, что важно для эффективного процесса разработки. Избегайте тестов, которые зависят от внешних систем, таких как базы данных или сетевые подключения, которые могут быть медленными и ненадежными. Вместо этого используйте макеты и заглушки для моделирования этих зависимостей.
### Структурируйте тесты аналогично коду приложения
Организация тестов таким образом, чтобы они отражали структуру кода приложения, помогает в их обслуживании. Используйте согласованные соглашения об именах и структуры каталогов, чтобы разработчикам было проще находить и понимать тесты.
### Разумно используйте инструменты покрытия
Инструменты тестового покрытия помогают определить, какая часть кодовой базы покрыта тестами. Однако достижение 100%-ного покрытия не должно быть конечной целью. Сосредоточьтесь на значимом покрытии, обеспечивающем тестирование критических путей и функциональных возможностей.
### Используйте автоматизацию и конвейеры CI/CD.
Интеграция тестов в конвейеры непрерывной интеграции и непрерывного развертывания (CI/CD) гарантирует, что тесты будут выполняться автоматически при каждом изменении кода. Такая практика помогает выявлять проблемы на ранней стадии и поддерживать качество кодовой базы.
## Популярные инструменты для тестирования приложений React
Для тестирования приложений React доступно несколько инструментов, каждый из которых обладает уникальными возможностями. Jest поддерживает надежное модульное тестирование и интеграционное тестирование с использованием таких функций, как макетирование и тестирование моментальных снимков. Библиотека тестирования React уделяет особое внимание тестированию компонентов с точки зрения пользователя, уделяя особое внимание поведению. Enzyme позволяет проводить детальные тесты взаимодействия компонентов с помощью поверхностного и полного DOM-рендеринга. Cypress обеспечивает сквозное тестирование, имитируя реальные взаимодействия пользователей в браузере. Storybook помогает создавать и тестировать компоненты пользовательского интерфейса изолированно. TestCafe предлагает сквозное кроссбраузерное и кроссплатформенное тестирование, обеспечивая всесторонний охват тестированием приложений React.
### Jest
Jest это широко используемый фреймворк для тестирования на JavaScript, который особенно популярен благодаря своей простоте и обширному набору функций, адаптированных для современной веб-разработки. Он предлагает встроенную поддержку имитационных функций и модулей, что помогает изолировать компоненты во время тестирования. Мощная библиотека утверждений Jest гарантирует, что ожидаемые результаты будут достигнуты, в то время как ее возможности тестирования моментальных снимков позволяют разработчикам фиксировать и сравнивать отображаемые выходные данные компонентов, обнаруживая неожиданные изменения с течением времени. Кроме того, установка Jest с нулевой конфигурацией, быстрое выполнение и полная отчетность о тестовом покрытии делают его идеальным выбором как для небольших, так и для крупномасштабных приложений React.
```js
// Example of a simple test using Jest
test('adds 1 + 2 to equal 3', () => {
expect(1 + 2).toBe(3);
});
```
### Библиотека тестирования React
Библиотека тестирования React разработана для того, чтобы стимулировать тестирование компонентов React с точки зрения пользователя, отдавая приоритет поведению и взаимодействиям, с которыми сталкиваются пользователи, а не внутренним деталям реализации. Имитируя действия пользователя, такие как щелчки, ввод текста и другие события, она помогает обеспечить корректное поведение компонентов в реальных сценариях. Библиотека продвигает лучшие практики, поощряя разработчиков запрашивать DOM способами, отражающими взаимодействие пользователей с приложением, например, находить элементы по их текстовому содержимому или ролям. Такой подход делает тесты более удобными в обслуживании и надежными, поскольку сводит к минимуму риск сбоя тестов из-за изменений во внутренних компонентах. Кроме того, легкий API библиотеки тестирования React и совместимость с популярными платформами тестирования, такими как Jest, делают ее незаменимым инструментом для создания ориентированных на пользователя тестов в приложениях React.
```jsx
// Example of using React Testing Library
import { render, fireEvent } from '@testing-library/react';
import Button from './Button';
test('Button changes label when clicked', () => {
const { getByText } = render(<Button />);
const buttonElement = getByText('Click me');
fireEvent.click(buttonElement);
expect(buttonElement.textContent).toBe('Clicked');
});
```
### Enzyme
Enzyme это утилита для тестирования React, которая поддерживает поверхностный, полный DOM и статический рендеринг, обеспечивая гибкость для различных задач тестирования. Интуитивно понятный API позволяет легко взаимодействовать с компонентами, моделируя события, просматривая дерево компонентов и утверждая поведение. Это делает Enzyme мощным инструментом для комплексного тестирования компонентов React.
```jsx
// Example of using Enzyme
import { shallow } from 'enzyme';
import Button from './Button';
test('Button renders correctly', () => {
const wrapper = shallow(<Button />);
expect(wrapper.text()).toBe('Click me');
});
```
### Cypress
Cypress это комплексный фреймворк для тестирования, который предоставляет комплексное решение для тестирования веб-приложений. Он позволяет писать тесты, которые имитируют реальные взаимодействия с пользователем и проверяют, работает ли приложение должным образом в реальной среде браузера.
```jsx
// Example of an E2E test using Cypress
describe('Login Flow', () => {
it('allows a user to log in', () => {
cy.visit('/login');
cy.get('input[placeholder="Username"]').type('testuser');
cy.get('input[placeholder="Password"]').type('password123');
cy.get('button').contains('Login').click();
cy.url().should('include', '/dashboard');
cy.contains('Welcome, testuser').should('be.visible');
});
});
```
### Storybook
Storybook это среда разработки компонентов пользовательского интерфейса. Она позволяет разработчикам создавать, визуализировать и тестировать компоненты изолированно, что упрощает создание и тестирование элементов пользовательского интерфейса без дополнительных затрат на запуск всего приложения.
```jsx
// Example of a Storybook story
import React from 'react';
import { storiesOf } from '@storybook/react';
import Button from './Button';
storiesOf('Button', module)
.add('default', () => <Button label="Click me" />)
.add('clicked', () => <Button label="Clicked" />);
```
### TestCafe
TestCafe выделяется как надежный комплексный инструмент тестирования, адаптированный для современных веб-приложений и обеспечивающий беспрепятственное создание и выполнение тестов в различных браузерах и платформах. Его универсальность позволяет разработчикам писать тесты один раз и запускать их в различных средах, оптимизируя процесс тестирования и обеспечивая согласованное поведение в разных браузерах. Простота и эффективность TestCafe делают его ценным инструментом для обеспечения надежности и функциональности веб-приложений.
```jsx
// Example of an E2E test using TestCafe
import { Selector } from 'testcafe';
fixture `Getting Started`
.page `http://devexpress.github.io/testcafe/example`;
test('My first test', async t => {
await t
.typeText('#developer-name', 'John Doe')
.click('#submit-button')
.expect(Selector('#article-header').innerText).eql('Thank you, John Doe!');
});
```
🚀 **Источник: [Тестирование приложений React: Лучшие практики и инструменты](https://open.zeba.academy/testirovanie-prilozheniy-react-luchshie-praktiki-instrumenty/)**