← Назад к вопросам

Что такое Mock объект?

1.8 Middle🔥 151 комментариев
#Тестирование

Комментарии (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. Главное — не переусложнять и не мокировать всё подряд.

Что такое Mock объект? | PrepBro