Что такое Mock? - IlyaKovanov/lib GitHub Wiki

Mock (или "мок") — это заглушка, которая притворяется реальным объектом, но на самом деле это фейк, который мы полностью контролируем.

Простая аналогия

Представьте, что вы режиссер и снимаете сцену, где актер должен звонить по телефону.

Без мока: Вы даете актеру реальный телефон, звоните настоящему человеку и надеетесь, что он скажет нужные слова.

С моком: Вы даете актеру игрушечный телефон, а сами стоите за кадром и говорите нужные фразы. Вы полностью контролируете диалог!

Простой пример на PHP

Допустим, у нас есть класс, который отправляет email:

class EmailService {
    public function sendEmail($to, $subject, $message) {
        // Здесь реальная отправка email через SMTP
        // Это долго и зависит от интернета
        return mail($to, $subject, $message);
    }
}

class UserRegistration {
    private $emailService;
    
    public function __construct(EmailService $emailService) {
        $this->emailService = $emailService;
    }
    
    public function registerUser($email, $name) {
        // Регистрируем пользователя...
        
        // Отправляем приветственное письмо
        $result = $this->emailService->sendEmail(
            $email, 
            'Добро пожаловать!', 
            "Привет, $name!"
        );
        
        return $result;
    }
}

Проблема при тестировании

Если мы тестируем UserRegistration, нам не нужно реально отправлять письма каждый раз! Это:

Медленно

Зависит от интернета

Засоряет почту

Ненадежно

Решение с Mock

// В тестах мы создаем мок EmailService
$emailServiceMock = $this->createMock(EmailService::class);

// Говорим моку: "Когда вызовут sendEmail с такими параметрами, верни true"
$emailServiceMock->method('sendEmail')
    ->with('[email protected]', 'Добро пожаловать!', 'Привет, Иван!')
    ->willReturn(true);

// Теперь тестируем наш основной класс
$registration = new UserRegistration($emailServiceMock);
$result = $registration->registerUser('[email protected]', 'Иван');

// Проверяем, что все работает
$this->assertTrue($result);

Что мы получили с Mock:

Скорость — не ждем реальную отправку email

Изоляция — тестируем только логику регистрации, а не отправку писем

Контроль — можем симулировать любые сценарии (успех, ошибка)

Предсказуемость — всегда знаем, что вернет мок

Основные способы использования Mock:

Замена медленных операций

// Вместо реальной базы данных
$dbMock = $this->createMock(Database::class);
$dbMock->method('query')->willReturn(['user' => 'Ivan']);

Симуляция ошибок

// Проверяем, как система реагирует на ошибки
$emailServiceMock->method('sendEmail')
    ->willThrowException(new \Exception('SMTP error'));

Проверка вызовов

// Убеждаемся, что метод был вызван
$emailServiceMock->expects($this->once())
    ->method('sendEmail');

Возврат разных значений

// Первый вызов вернет true, второй - false
$emailServiceMock->method('sendEmail')
    ->will($this->onConsecutiveCalls(true, false));