Mock (мок, mock-объект) — это специальный тестовый объект, который имитирует поведение реального объекта в контролируемых условиях. Моки являются ключевым инструментом в изолированном тестировании компонентов.
Для изоляции тестируемого кода от внешних зависимостей:
Для ускорения тестов (избегая реальных HTTP-запросов или запросов к БД)
Для тестирования edge-cases, которые сложно воспроизвести с реальными объектами
describe PaymentProcessor do
let(:payment_gateway) { instance_double('PaymentGateway') }
it 'processes payment successfully' do
# Настраиваем ожидание вызова метода с конкретными параметрами
expect(payment_gateway).to receive(:charge)
.with(amount: 100, card: '4242424242424242')
.and_return(true)
processor = PaymentProcessor.new(payment_gateway)
result = processor.process(amount: 100, card: '4242424242424242')
expect(result).to be true
end
end
describe Notifier do
it 'sends exactly one email per user' do
email_service = class_double('EmailService')
allow(email_service).to receive(:send).and_return(true)
notifier = Notifier.new(email_service)
notifier.notify_users([User.new, User.new])
expect(email_service).to have_received(:send).twice
end
end
Не злоупотребляйте моками:
Соблюдайте принцип "один мок на тест":
Используйте verifying doubles (в RSpec):
# Вместо этого:
double('User', name: 'John')
# Используйте это:
instance_double('User', name: 'John') # Проверяет существование метода
Избегайте хрупких тестов:
Over-mocking:
# Плохо: мокаем все подряд
describe Order do
it 'calculates total' do
item = double('Item', price: 10)
allow(Item).to receive(:find).and_return(item)
# ...
end
end
Тестирование реализации вместо поведения:
# Плохо: тест знает слишком много о внутренней работе
it 'calls save_exactly twice' do
expect(user).to receive(:save).twice
# ...
end
Использование моков для простых объектов:
Резюмируем: Моки — это мощный инструмент для изолированного тестирования, но они требуют аккуратного использования. В Ruby-экосистеме RSpec предоставляет отличные средства для работы с моками (doubles, spies, verifying doubles). Главное — соблюдать баланс между изоляцией и реализмом тестов, фокусируясь на тестировании поведения, а не реализации.