🔬 Юнит-тестирование

Принципы, структура AAA, моки, покрытие, примеры на JS, Python и Java.

Шпаргалки · Тестирование · #testing #unit #tdd

Идея

Юнит-тест проверяет небольшую единицу (функция, метод, класс) изолированно, быстро и без сети и БД.

Принципы F.I.R.S.T.

Fast (быстрые), Independent (независимые), Repeatable (повторяемые), Self-validating (сами решают пройден или нет), Timely (пишутся вовремя).

Структура AAA

  1. Arrange подготовка данных и объектов.
  2. Act вызов проверяемого кода.
  3. Assert сравнение с ожидаемым.

JavaScript (Vitest / Jest)

import { describe, it, expect, vi } from 'vitest';
import { discount } from './price';

describe('discount', () => {
  it('даёт 10% на заказ от 1000', () => {
    expect(discount(1000)).toBe(100);
  });
  it('не даёт скидку на малый заказ', () => {
    expect(discount(500)).toBe(0);
  });
  it('вызывает логгер', () => {
    const log = vi.fn();
    discount(1000, log);
    expect(log).toHaveBeenCalledWith('discount applied');
  });
});

Python (pytest)

import pytest
from price import discount

@pytest.mark.parametrize("total, expected", [(1000, 100), (500, 0)])
def test_discount(total, expected):
    assert discount(total) == expected

def test_negative_total_raises():
    with pytest.raises(ValueError):
        discount(-1)

Java (JUnit 5 + Mockito)

@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
    @Mock PaymentGateway gateway;
    @InjectMocks OrderService service;

    @Test
    void chargesCustomer() {
        when(gateway.charge(100)).thenReturn(true);
        assertTrue(service.pay(100));
        verify(gateway).charge(100);
    }
}

Двойники тестов

Тип Назначение
Dummy заглушка-параметр, не используется
Stub возвращает заранее заданный ответ
Mock проверяет, как его вызывали
Spy реальный объект с подсмотром вызовов
Fake упрощённая рабочая реализация (БД в памяти)

Покрытие кода

Строки, ветки, условия. Покрытие показывает, что не проверено, но не гарантирует качество тестов. Разумная цель 70–85% по критичному коду.

Хорошие практики

  • Один тест проверяет одно поведение, название описывает его.
  • Без зависимости от порядка запуска и времени (подмените часы).
  • Тестируйте поведение, а не внутреннюю реализацию.
  • Граничные значения и ошибки, а не только «счастливый путь».
  • TDD: красный (тест падает) → зелёный (минимальный код) → рефакторинг.

Инструменты по языкам

JS: Vitest, Jest, Mocha. Python: pytest, unittest. Java: JUnit, TestNG, Mockito. C#: xUnit, NUnit, Moq. Go: testing, testify. PHP: PHPUnit, Pest.