Mocks e Fixtures em Testes PHP: Guia Completo para Iniciantes

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Por que testar sem mocks é como cozinhar sem sal

\n\n

Imagine que você está desenvolvendo uma aplicação que envia notificações por e-mail, interage com um banco de dados e consome uma API externa. Como testar tudo isso sem usar mocks e fixtures em PHP? Você teria que enviar e-mails reais, criar registros no banco de dados e aguardar respostas de serviços externos a cada execução. Isso é lento, instável e, francamente, ineficiente.

\n\n

É aqui que entram os test doubles — substitutos para objetos reais. No ecossistema PHP, a combinação ideal é: mocks para verificar interações e fixtures para preparar os dados. Vamos entender como isso funciona na prática.

\n\n

Mock vs Stub vs Fake: entenda as diferenças

\n\n

Antes de mergulharmos no código, é importante esclarecer os conceitos. No universo dos testes unitários em PHP, existem três tipos principais de substitutos:

\n\n
    \n
  • Stub — retorna dados pré-definidos. Você testa se seu código processa esses dados corretamente.
  • \n
  • Mock — além de retornar dados, verifica como seu sistema chama os métodos: quantas vezes, com quais argumentos e em qual ordem.
  • \n
  • Fake — uma implementação simplificada e funcional (como um banco de dados em memória).
  • \n
\n\n

No PHPUnit, que é o padrão de facto para testes em PHP, esses termos às vezes se misturam. Mas vamos ser precisos: mocks em PHP são aqueles onde você define expectativas (expectations).

\n\n

Criando seu primeiro mock com PHPUnit

\n\n

Suponha que temos uma classe Mailer responsável por enviar e-mails. Queremos verificar se o serviço de registro chama o método send() exatamente uma vez com os dados corretos.

\n\n
<?php\nuse PHPUnit\\Framework\\TestCase;\n\nclass UserRegistrationTest extends TestCase\n{\n    public function testSendWelcomeEmailOnRegistration(): void\n    {\n        // Criando um mock para Mailer\n        $mailer = $this->createMock(Mailer::class);\n        \n        // Configurando a expectativa: método send será chamado 1 vez\n        $mailer->expects($this->once())\n               ->method('send')\n               ->with(\n                   $this->equalTo('user@example.com'),\n                   $this->stringContains('Welcome')\n               );\n        \n        $service = new UserRegistrationService($mailer);\n        $service->register('user@example.com', 'password123');\n    }\n}\n
\n\n

Perceba: não estamos testando se o e-mail foi realmente enviado. Estamos verificando se nosso código tentou enviá-lo — essa é a essência dos mocks em testes PHP. Se o método send() não for chamado (ou for chamado duas vezes), o teste falhará.

\n\n

O método expects e suas possibilidades

\n\n

O PHPUnit oferece uma API rica para configurar expectativas:

\n\n
    \n
  • $this->once() — exatamente uma chamada
  • \n
  • $this->exactly(3) — exatamente três chamadas
  • \n
  • $this->atLeastOnce() — pelo menos uma chamada
  • \n
  • $this->never() — o método não deve ser chamado
  • \n
\n\n

Para os argumentos, use os matchers (constraints):

\n\n
$mailer->expects($this->once())\n       ->method('send')\n       ->with(\n           $this->callback(function($email) {\n               return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;\n           }),\n           $this->anything() // não nos importamos com o segundo argumento\n       );\n
\n\n

Fixtures em PHP: preparando os dados antes que você precise

\n\n

Fixtures são estados de dados predefinidos nos quais o sistema se encontra antes da execução do teste. No PHPUnit, usamos os métodos setUp() e

Blogs

Book Recommendations