Ответ
Мокирование — это техника в модульном тестировании, при которой реальные зависимости объекта заменяются контролируемыми объектами-заглушками (моками). Это позволяет изолировать тестируемый код, задавать ожидаемое поведение зависимостей и проверять взаимодействие с ними.
Зачем это нужно: Например, чтобы протестировать сервис оплаты, не совершая реальных транзакций через платежный шлюз. Мы создаем мок шлюза, который всегда возвращает успешный ответ.
Пример с PHPUnit и моком:
// Интерфейс внешней зависимости
interface PaymentGatewayInterface {
public function charge(float $amount): bool;
}
// Класс, который мы тестируем
class PaymentService {
private PaymentGatewayInterface $gateway;
public function __construct(PaymentGatewayInterface $gateway) {
$this->gateway = $gateway;
}
public function processOrder(float $amount): bool {
// Бизнес-логика...
return $this->gateway->charge($amount);
}
}
// Тест с использованием мока
class PaymentServiceTest extends PHPUnitFrameworkTestCase {
public function testProcessOrderCallsGatewayWithCorrectAmount(): void {
// 1. Создаем мок объекта
$gatewayMock = $this->createMock(PaymentGatewayInterface::class);
// 2. Настраиваем ожидания: метод charge будет вызван ровно один раз с аргументом 100.0 и вернет true
$gatewayMock->expects($this->once())
->method('charge')
->with($this->equalTo(100.0))
->willReturn(true);
// 3. Внедряем мок и тестируем
$service = new PaymentService($gatewayMock);
$result = $service->processOrder(100.0);
// 4. Проверяем результат
$this->assertTrue($result);
}
}
В своей работе я часто использую моки для тестирования сервисов, которые работают с базой данных, внешними API, почтовыми рассылками или файловой системой. Это делает тесты быстрыми и независимыми от внешнего окружения.
Ответ 18+ 🔞
А, мокирование, ёпта! Ну это же просто святое дело для любого, кто хоть раз пытался написать тест, который не ломается из-за того, что у соседнего сервера траванулся жёсткий диск. Сейчас объясню на пальцах, без этой заумной книжной хуйни.
Представь, тебе надо проверить, правильно ли твой код звонит в банк, чтобы списать бабки. Но ты же не будешь при каждом запуске теста реально тысячу рублей с карты снимать? Это же пиздец, через неделю тестирования ты станешь бомжом. Вот для этого и нужны моки — такие подставные уроды, которые притворяются настоящими сервисами.
Суть в чём: Берёшь свою хитрую жопу, которая зависит от какой-то внешней херни (база данных, платёжка, отправка смс), и подсовываешь ей вместо настоящей зависимости её кривую картонную копию, которой ты полностью управляешь. И говоришь ей: «Слушай, вот этот твой PaymentGateway — он теперь будет всегда говорить «ок», когда я попрошу, и никуда на самом деле звонить не будет». И ты спокоен.
Вот смотри, как это выглядит в коде, на примере этой платежной хрени:
// Это интерфейс, контракт на то, как должна выглядеть платёжная заглушка
interface PaymentGatewayInterface {
public function charge(float $amount): bool;
}
// А это наш главный герой — сервис, который надо протестировать
class PaymentService {
private PaymentGatewayInterface $gateway;
public function __construct(PaymentGatewayInterface $gateway) {
$this->gateway = $gateway;
}
public function processOrder(float $amount): bool {
// Тут какая-то своя логика, почесали репу, посчитали скидку...
// А потом БАЦ — идём в шлюз деньги списывать
return $this->gateway->charge($amount);
}
}
// А ТЕПЕРЬ САМОЕ ВКУСНОЕ — ТЕСТ!
class PaymentServiceTest extends PHPUnitFrameworkTestCase {
public function testProcessOrderCallsGatewayWithCorrectAmount(): void {
// 1. Творим муляж! Берём и создаём мок.
// Теперь $gatewayMock — это не настоящий шлюз, а его злобный клон-оборотень.
$gatewayMock = $this->createMock(PaymentGatewayInterface::class);
// 2. Настраиваем этого ублюдка. Говорим ему строго:
// «Метод `charge` должен быть вызван РОВНО ОДИН РАЗ (`$this->once()`),
// и вызван с аргументом 100.0 (`->with($this->equalTo(100.0))`),
// и когда вызовут — ты должен вернуть `true` (`->willReturn(true)`)».
// Если что-то пойдёт не так — PHPUnit взбесится и тест провалится.
$gatewayMock->expects($this->once())
->method('charge')
->with($this->equalTo(100.0))
->willReturn(true);
// 3. Подсовываем нашему сервису эту липу вместо настоящего шлюза.
$service = new PaymentService($gatewayMock);
// Запускаем логику.
$result = $service->processOrder(100.0);
// 4. Смотрим, что получилось. Если всё ок — тест зелёный.
$this->assertTrue($result);
// И ты сидишь довольный, потому что проверил логику, не потратив ни копейки.
}
}
Вот и вся магия, ебать мои старые костыли. Я эту хуйню постоянно юзаю: когда тестирую что-то, что лезет в базу (чтобы не засирать её тестовыми данными), когда работаю с внешним АПИ (которое может тупить или вообще лежать), или с отправкой писем (чтобы весь ящик не заспамить). Тесты летают как угорелые, потому что от внешнего мира не зависят вообще. Доверия ебать ноль к этим внешним сервисам, а с моками — полный контроль. Красота же!