Введение
Тестирование - важная часть разработки веб-приложений. В этой статье мы рассмотрим различные подходы к тестированию, инструменты и лучшие практики.
Почему тестирование важно?
- Качество: Раннее обнаружение ошибок
- Безопасность: Предотвращение регрессий
- Документация: Тесты как живая документация
- Рефакторинг: Уверенность при изменении кода
Уровни тестирования
1. Unit-тесты
Что такое unit-тесты?
- Тестирование отдельных компонентов
- Изоляция от внешних зависимостей
- Быстрое выполнение
- Легкое поддержание
Примеры unit-тестов
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // math.js
export function add(a, b) {
return a + b;
}
// math.test.js
import { add } from './math';
describe('Math functions', () => {
test('adds two numbers correctly', () => {
expect(add(1, 2)).toBe(3);
expect(add(-1, 1)).toBe(0);
});
});
|
2. Интеграционные тесты
Что такое интеграционные тесты?
- Тестирование взаимодействия компонентов
- Проверка API endpoints
- Работа с базой данных
- Тестирование middleware
Примеры интеграционных тестов
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| const request = require('supertest');
const app = require('./app');
describe('User API', () => {
test('creates a new user', async () => {
const response = await request(app)
.post('/api/users')
.send({
name: 'John',
email: 'john@example.com'
});
expect(response.status).toBe(201);
expect(response.body).toHaveProperty('id');
});
});
|
3. End-to-End тесты
Что такое E2E тесты?
- Тестирование всего приложения
- Имитация действий пользователя
- Проверка реальных сценариев
- Тестирование UI/UX
Примеры E2E тестов
1
2
3
4
5
6
7
8
9
10
11
| describe('User Registration', () => {
it('registers a new user', () => {
cy.visit('/register');
cy.get('input[name="name"]').type('John');
cy.get('input[name="email"]').type('john@example.com');
cy.get('button[type="submit"]').click();
cy.url().should('include', '/dashboard');
cy.contains('Welcome, John');
});
});
|
Инструменты тестирования
1. Jest
Установка и настройка
1
| npm install --save-dev jest
|
1
2
3
4
5
6
7
| {
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage"
}
}
|
Конфигурация Jest
1
2
3
4
5
6
7
8
| // jest.config.js
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
moduleNameMapper: {
'\\.(css|less|scss|sass)$': 'identity-obj-proxy'
}
};
|
2. React Testing Library
Установка
1
| npm install --save-dev @testing-library/react @testing-library/jest-dom
|
Примеры тестов компонентов
1
2
3
4
5
6
7
8
9
| import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';
test('increments counter when button is clicked', () => {
render(<Counter />);
const button = screen.getByText('Increment');
fireEvent.click(button);
expect(screen.getByText('1')).toBeInTheDocument();
});
|
3. Cypress
Установка
1
| npm install --save-dev cypress
|
Настройка Cypress
1
2
3
4
5
6
7
8
| // cypress.config.js
module.exports = {
e2e: {
baseUrl: 'http://localhost:3000',
supportFile: 'cypress/support/e2e.js',
specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}'
}
};
|
Методологии тестирования
1. Test-Driven Development (TDD)
Цикл TDD
- Написание теста
- Запуск теста (ожидается ошибка)
- Написание кода
- Запуск теста (ожидается успех)
- Рефакторинг
Пример TDD
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // calculator.test.js
describe('Calculator', () => {
test('multiplies two numbers', () => {
const calculator = new Calculator();
expect(calculator.multiply(2, 3)).toBe(6);
});
});
// calculator.js
class Calculator {
multiply(a, b) {
return a * b;
}
}
|
2. Behavior-Driven Development (BDD)
Синтаксис BDD
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| describe('User Registration', () => {
it('should create a new user account', () => {
// Given
const user = {
name: 'John',
email: 'john@example.com'
};
// When
const result = registerUser(user);
// Then
expect(result.success).toBe(true);
expect(result.user).toHaveProperty('id');
});
});
|
Тестирование API
1. REST API
Тестирование endpoints
1
2
3
4
5
6
7
8
9
10
| describe('User API', () => {
test('GET /api/users returns list of users', async () => {
const response = await request(app)
.get('/api/users')
.set('Authorization', `Bearer ${token}`);
expect(response.status).toBe(200);
expect(Array.isArray(response.body)).toBe(true);
});
});
|
2. GraphQL API
Тестирование запросов
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| describe('User Queries', () => {
test('fetches user by ID', async () => {
const response = await graphqlRequest(`
query GetUser($id: ID!) {
user(id: $id) {
name
email
}
}
`, { id: '1' });
expect(response.data.user).toHaveProperty('name');
expect(response.data.user).toHaveProperty('email');
});
});
|
Тестирование производительности
1. Нагрузочное тестирование
Пример с k6
1
2
3
4
5
6
7
8
9
10
11
| import http from 'k6/http';
import { check, sleep } from 'k6';
export default function() {
const response = http.get('http://test.k6.io');
check(response, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500
});
sleep(1);
}
|
2. Тестирование производительности браузера
Lighthouse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // lighthouse.config.js
module.exports = {
ci: {
collect: {
startServerCommand: 'npm run start',
url: ['http://localhost:3000']
},
assert: {
assertions: {
'categories:performance': ['error', { minScore: 0.9 }]
}
}
}
};
|
Автоматизация тестирования
1. CI/CD интеграция
GitHub Actions
1
2
3
4
5
6
7
8
9
10
11
12
13
| name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '14'
- run: npm install
- run: npm test
- run: npm run test:e2e
|
2. Отчеты о тестировании
Настройка отчетов
1
2
3
4
5
6
7
8
9
10
| // jest.config.js
module.exports = {
reporters: [
'default',
['jest-junit', {
outputDirectory: 'reports',
outputName: 'junit.xml'
}]
]
};
|
Заключение
Тестирование - важная часть разработки веб-приложений. Используйте различные уровни тестирования и инструменты для обеспечения качества вашего кода. Помните, что хорошие тесты помогают не только находить ошибки, но и документировать поведение приложения.
Полезные ресурсы