Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Mock объекты: полное понимание
Mock объект — это поддельный объект, который имитирует поведение реального объекта и используется в тестировании.
Основная концепция
Mock помогает изолировать код от зависимостей. Вместо реальной БД используем mock, который возвращает предсказуемые данные.
Типы тестовых объектов
Stub — возвращает фиксированные значения
// Stub: просто возвращает значение
$userRepositoryStub = $this->createStub(UserRepository::class);
$userRepositoryStub->method("findById")->willReturn(new User(1, "John"));
Mock — проверяет, как его вызывают
// Mock: проверяет, что метод вызван с нужными параметрами
$emailMock = $this->createMock(EmailService::class);
$emailMock->expects($this->once())
->method("send")
->with("user@test.com", "Welcome");
Spy — записывает вызовы и возвращает реальный результат
// Spy: отслеживает вызовы реального объекта
$spy = $this->spy(PaymentService::class);
partialMock($spy)->shouldReceive("charge");
Практический пример с PHPUnit
class OrderServiceTest extends TestCase {
public function testOrderCreation() {
// Создаём mock для репозитория
$repositoryMock = $this->createMock(OrderRepository::class);
$repositoryMock->expects($this->once())
->method("save")
->with($this->isInstanceOf(Order::class))
->willReturn(true);
// Создаём mock для email сервиса
$emailMock = $this->createMock(EmailService::class);
$emailMock->expects($this->once())
->method("sendConfirmation")
->with("user@test.com");
// Используем mocks в тесте
$service = new OrderService($repositoryMock, $emailMock);
$order = new Order(123, "user@test.com", 99.99);
$result = $service->createOrder($order);
$this->assertTrue($result);
}
}
Mockery для более сложных случаев
use Mockery\\MockInterface;
class PaymentTest extends TestCase {
public function testPaymentProcessing() {
$paymentGatewayMock = Mockery::mock(PaymentGateway::class);
$paymentGatewayMock
->shouldReceive("charge")
->with(100.00, "4111111111111111")
->once()
->andReturn(["status" => "success", "id" => "txn_123"]);
$processor = new PaymentProcessor($paymentGatewayMock);
$result = $processor->processPayment(100.00, "4111111111111111");
$this->assertEquals("success", $result["status"]);
Mockery::close();
}
}
Зачем нужны mock объекты?
- Изоляция кода: тестируешь логику без внешних зависимостей
- Скорость: mock быстрее, чем реальный API или БД
- Предсказуемость: mock всегда возвращает одно и то же
- Контроль: можно проверить, как вызван метод
- Тестирование ошибок: легко имитировать исключения
Пример: тестирование обработки ошибок
public function testErrorHandling() {
$apiMock = $this->createMock(ExternalAPI::class);
// Имитируем исключение
$apiMock->method("fetchData")->willThrowException(
new Exception("API is down")
);
$service = new DataService($apiMock);
$this->expectException(ServiceException::class);
$service->getData();
}
Best Practices
- Мок только зависимости, тестируй реальный код
- Не мокируй классы из самого проекта без причины
- Используй частичные mocks осторожно
- Проверяй expectations перед assertTrue
- Очищай mocks после каждого теста (Mockery::close())
Когда НЕ использовать mock?
- Не мокируй простые value objects
- Не мокируй код, который ты пишешь
- Не создавай лишние mocks (KISS)
Вывод
Mock объекты — это инструмент для изоляции кода в unit тестах. Они позволяют тестировать логику независимо от внешних сервисов, БД и API. Главное — не переусложнять и не мокировать всё подряд.