- **Определение**: Упрощенная реализация зависимости, возвращающая заранее заданные ответы
- **Когда использовать**:
- Замена медленных сервисов
- Эмуляция определенных состояний системы
- Тестирование в изоляции
- **Пример**: Фиксированный ответ платежного шлюза "Успех"
- **Определение**: Умная заглушка с проверкой взаимодействий
- **Когда использовать**:
- Проверка вызовов внешних сервисов
- Верификация последовательности действий
- Тестирование побочных эффектов
- **Пример**: Проверка что email-сервис был вызван ровно 1 раз
Характеристика | Stub | Mock |
---|---|---|
Цель | Подмена зависимостей | Проверка взаимодействий |
Проверка вызовов | Нет | Да |
Гибкость | Статические данные | Динамическое поведение |
Сложность | Простые | Сложные |
Использование | Для данных | Для поведения |
- **Mockito** (Java):
// Пример создания mock UserService mockService = Mockito.mock(UserService.class); Mockito.when(mockService.getUser(1)).thenReturn(new User("test"));
- **Sinon.js** (JavaScript):
// Stub пример const stub = sinon.stub(userRepository, 'find').returns(Promise.resolve({id: 1}));
- **unittest.mock** (Python):
from unittest.mock import Mock mock = Mock(return_value=42)
### 3.2 Специализированные решения
WireMock (HTTP сервисы):
stubFor(get(urlEqualTo("/api/resource"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("{'data': 'value'}")));
TestContainers (для баз данных):
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:13");
Mountebank (Мультипротокольные моки):
imposter = {
protocol: 'http',
port: 3000,
stubs: [{
responses: [{
is: { statusCode: 200, body: { result: 'OK' } }
}]
}]
};
// Создаем mock платежного шлюза
PaymentGateway mockGateway = mock(PaymentGateway.class);
// Настраиваем ожидаемый вызов
when(mockGateway.process(any(Payment.class)))
.thenReturn(SUCCESS);
// Проверяем поведение
orderService.processOrder(order);
verify(mockGateway, times(1)).process(any());
// Создаем stub с тестовыми данными
UserRepository stubRepo = new UserRepositoryStub();
stubRepo.addUser(new User("test", "admin"));
// Внедряем stub в тестируемый сервис
AuthService authService = new AuthService(stubRepo);
// Проверяем логику
assertTrue(authService.login("test", "admin"));
✅ **Stub**:
- Нужны только данные
- Тестируемый код не вызывает внешние сервисы
- Простые сценарии
✅ **Mock**:
- Важно проверить взаимодействие
- Тестируются побочные эффекты
- Сложные сценарии с несколькими вызовами
❌ Слишком детальные проверки в mock (хрупкие тесты)
❌ Использование mock когда достаточно stub
❌ Игнорирование очистки состояния между тестами
❌ Мокирование того, что не принадлежит тесту
mocks и stubs — важнейшие инструменты для изолированного тестирования. Правильное их применение позволяет создавать быстрые, стабильные и содержательные тесты, не зависящие от внешних систем. Выбор между ними зависит от целей тестирования — проверка состояния (stub) или поведения (mock).