Как проверяешь свою работу на наличие ошибок?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как проверяешь свою работу на наличие ошибок?
Проверка качества — это системный процесс, а не одноразовая задача. У меня есть многоуровневая стратегия, которая предотвращает ошибки на разных этапах.
Уровень 1: Во время разработки (TDD)
Я пишу тесты ДО кода — это мой главный инструмент.
// СНАЧАЛА пишу падающий тест
test('getUserRoles should return array of role names', () => {
const user = { id: '123', roles: ['admin', 'moderator'] };
const roles = getUserRoles(user);
expect(roles).toEqual(['admin', 'moderator']);
});
// ПОТОМ пишу минимальный код для прохождения
function getUserRoles(user: User): string[] {
return user.roles.map(r => r.name);
}
// ПОТОМ рефакторю, пока тесты зелёные
Преимущества TDD:
- Я знаю, что код работает
- Изменения не ломают старый функционал
- Тесты = живая документация
- Меньше багов в production
Уровень 2: Линтинг и статический анализ
# ESLint — ловит синтаксические и логические ошибки
npm run lint
# TypeScript — ловит ошибки типов
npm run build
# Автоматическое форматирование
npm run format
Типичные ошибки, которые ESLint ловит:
// Неиспользованные переменные
const unused = 42; // ❌ ESLint ошибка
// null/undefined безопасность
const user = await getUser(); // может быть null
const email = user.email; // ❌ может быть ошибка
// TypeScript
const user: User = someFunction(); // проверяет тип
const name: string = user.name; // если name неправильного типа
Уровень 3: Unit тесты
Тестирую отдельные функции и модули.
// Тест функции для проверки пароля
import { describe, it, expect } from 'vitest';
describe('validatePassword', () => {
it('should return true for valid password', () => {
expect(validatePassword('Str0ng!Pass')).toBe(true);
});
it('should return false for password < 8 chars', () => {
expect(validatePassword('Short1!')).toBe(false);
});
it('should return false for no uppercase', () => {
expect(validatePassword('lowercase123!')).toBe(false);
});
it('should return false for no numbers', () => {
expect(validatePassword('NoNumbers!')).toBe(false);
});
});
// Запуск
// npm test — проходят все? Отлично!
Цель: 90%+ покрытие кода
npm run test:coverage
# ┌──────────────┬────────┐
# │ File │ Lines │
# ├──────────────┼────────┤
# │ validators │ 95% │
# │ services │ 92% │
# │ controllers │ 88% │
Уровень 4: Integration тесты
Тестирую взаимодействие модулей.
// Тест API endpoint
import { describe, it, expect, beforeAll } from 'vitest';
import request from 'supertest';
import app from '../app';
describe('POST /api/v1/auth/login', () => {
beforeAll(async () => {
// Setup: создаю тестового пользователя
await db.query('INSERT INTO users VALUES ...');
});
it('should return 200 with token for valid credentials', async () => {
const response = await request(app)
.post('/api/v1/auth/login')
.send({ email: 'user@test.com', password: 'Password123!' });
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('token');
expect(response.body.token).toMatch(/^eyJ/);
});
it('should return 401 for invalid credentials', async () => {
const response = await request(app)
.post('/api/v1/auth/login')
.send({ email: 'user@test.com', password: 'wrong' });
expect(response.status).toBe(401);
expect(response.body).toHaveProperty('error');
});
it('should return 400 for missing email', async () => {
const response = await request(app)
.post('/api/v1/auth/login')
.send({ password: 'Password123!' });
expect(response.status).toBe(400);
});
});
Уровень 5: Database тесты
Тестирую SQL запросы и логику БД.
describe('Database queries', () => {
it('should save user to database', async () => {
const user = {
email: 'new@test.com',
name: 'Test User',
role: 'user'
};
const result = await db.query(
'INSERT INTO users (email, name, role) VALUES ($1, $2, $3) RETURNING *',
[user.email, user.name, user.role]
);
expect(result.rows[0].email).toBe('new@test.com');
expect(result.rows[0]).toHaveProperty('id'); // auto-generated
});
it('should find user by email', async () => {
const result = await db.query(
'SELECT * FROM users WHERE email = $1',
['test@test.com']
);
expect(result.rows).toHaveLength(1);
expect(result.rows[0].email).toBe('test@test.com');
});
it('should handle null values correctly', async () => {
// БД не должна позволить NULL в обязательных полях
const result = await db.query(
'INSERT INTO users (email, name, role) VALUES ($1, $2, $3)',
[null, 'Test', 'user']
).catch(err => err);
expect(result.code).toBe('23502'); // NOT NULL violation
});
});
Уровень 6: Code Review (от коллег)
Мой код проходит через глаза других разработчиков.
Я ищу:
✓ Логические ошибки, которые я пропустил
✓ Performance проблемы
✓ Нарушение архитектуры
✓ Security уязвимости
✓ Читаемость кода
Пример review:
Другой разработчик:
> Почему ты используешь var вместо const?
> Это может привести к ошибкам scope.
Я:
> Ты прав, исправляю на const.
Уровень 7: Pre-commit hooks
Автоматические проверки перед каждым коммитом.
# .husky/pre-commit
#!/bin/sh
# Lint изменённые файлы
npm run lint
if [ $? -ne 0 ]; then
echo "Lint failed, aborting commit"
exit 1
fi
# Запусти unit тесты
npm run test
if [ $? -ne 0 ]; then
echo "Tests failed, aborting commit"
exit 1
fi
echo "All checks passed!"
Теперь я не могу закоммитить код с ошибками.
Уровень 8: CI/CD Pipeline
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '20'
- run: npm install
- run: npm run lint
- run: npm run test -- --coverage
- run: npm run build
# Отправь отчёт о coverage
- uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
Прежде чем merge в main, код должен пройти все тесты.
Уровень 9: Manual smoke testing
Носителя я тестирую вручную.
# Запусти локально
npm run dev
# Попробуй основные сценарии
1. Регистрация юзера
2. Логин
3. Создание ресурса
4. Обновление
5. Удаление
6. Ошибочные случаи (валидация, права доступа)
7. Edge cases (пустые значения, очень большие числа)
Уровень 10: Production мониторинг
// Даже с тестами в продакшене могут быть проблемы
// Логирование ошибок
import Sentry from '@sentry/node';
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.1
});
app.use((err, req, res, next) => {
Sentry.captureException(err);
res.status(500).json({ error: 'Internal server error' });
});
// Алерты при проблемах
// - Если ошибки > 100 в час
// - Если response time > 1 сек
// - Если CPU > 80%
Мой полный процесс проверки перед push
# 1. Список изменений
git diff
# 2. Все ли файлы, что нужно?
git status
# 3. Линтинг
npm run lint
# 4. Форматирование
npm run format
# 5. Тесты с покрытием
npm run test -- --coverage
# Если < 90% — рефакторю, добавляю тесты
# 6. Build (проверка TypeScript)
npm run build
# 7. Manual тест критичных путей
curl http://localhost:3000/api/health
# Проверяю логин, CRUD операции
# 8. Commit с понятным сообщением
git commit -m "feat: add user authentication"
# 9. Push
git push origin feature-branch
# 10. Жду CI/CD пройти
Типичные ошибки, которые я ловлю
✓ Typos в переменных (TypeScript ловит) ✓ Забытые await для async функций ✓ Off-by-one ошибки в loops ✓ Null/undefined references ✓ SQL Injection (параметризованные запросы) ✓ Race conditions (SELECT FOR UPDATE) ✓ Memory leaks (забытые listeners) ✓ Performance проблемы (N+1 queries)
Итоговый результат: баги попадают в продакшн редко, и если попадают, я их сразу вижу в мониторинге.