0Pricing
PHP Academy · Aula

Simulação e criação de dublês com Mockery

Isole unidades com dublês de teste flexíveis.

Simulação e criação de dublês com Mockery é uma aula grátis de PHP Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de PHP Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de PHP Academy inclui 4 aulas no total.

Por que uma biblioteca de simulação dedicada

O PHPUnit fornece sua própria API de dublês de teste, mas o Mockery oferece uma sintaxe mais fluente e expressiva, além de recursos que as simulações do PHPUnit não têm — simulações parciais, espiões, correspondência flexível de argumentos e expectativas ordenadas. Para códigos complexos com muitas colaborações, o Mockery costuma ser muito mais legível. Esta lição aborda todo o espectro de dublês e quando usar cada um.

composer require --dev mockery/mockery

Dublê de retorno vs simulação vs espião

Um vocabulário preciso evita testes confusos:

  • Dublê de retorno — retorna valores predefinidos; você verifica o estado (o resultado).
  • Simulação — tem expectativas sobre chamadas; você verifica o comportamento (se foi chamada corretamente). Expectativas não atendidas fazem o teste falhar.
  • Espião — registra chamadas e permite verificá-las depois do fato.

Como regra geral: prefira dublês de retorno para consultas e simulações ou espiões para comandos.

Um dublê de retorno com allows()

Use Mockery::mock() e allows() (ou shouldReceive()->andReturn()) para fornecer valores de retorno predefinidos sem verificar se a chamada ocorreu. Aqui, um dublê de uma porta de acesso fornece uma taxa de câmbio conhecida para que possamos testar o cálculo isoladamente.

<?php
use Mockery;
use PHPUnit\Framework\TestCase;

final class ConverterTest extends TestCase
{
    public function test_converts_using_rate(): void
    {
        $rates = Mockery::mock(RateGateway::class);
        $rates->allows()->rateFor('USD', 'EUR')->andReturn(0.9);

        $sut = new Converter($rates);
        self::assertSame(90.0, $sut->convert(100.0, 'USD', 'EUR'));

        Mockery::close();
    }
}

Uma simulação com expects()

Quando a própria interação é o contrato — por exemplo, "um e-mail deve ser enviado exatamente uma vez" — use expects() ou shouldReceive()->once(). O Mockery verifica a expectativa durante Mockery::close(); uma chamada não atendida faz o teste falhar.

<?php
use Mockery;

$mailer = Mockery::mock(Mailer::class);
$mailer->expects()
       ->send(Mockery::type(Message::class))
       ->once();

$service = new SignupService($mailer);
$service->register('ada@example.com');

Mockery::close(); // fails here if send() was never called

Comparadores de argumentos

Os comparadores do Mockery permitem que as expectativas sejam tão flexíveis ou rigorosas quanto necessário:

  • Mockery::any() — qualquer valor.
  • Mockery::type('string') / um nome de classe — verificação de tipo.
  • Mockery::on(fn($a) => ...) — predicado personalizado.
  • Mockery::capture($var) — captura o argumento para verificações posteriores.
<?php
use Mockery;

$repo = Mockery::mock(UserRepo::class);
$repo->expects()
     ->save(Mockery::on(fn(User $u) => $u->isActive()))
     ->once()
     ->andReturnTrue();

Sequências de retorno e retornos dinâmicos

Você pode programar vários valores de retorno em chamadas sucessivas ou calcular o retorno a partir dos argumentos com andReturnUsing(). Isso modela lógica de novas tentativas, paginação ou colaboradores com estado.

<?php
use Mockery;

$api = Mockery::mock(HttpClient::class);
// First call throws, second succeeds (retry test):
$api->shouldReceive('get')
    ->twice()
    ->andThrow(new \RuntimeException('timeout'))
    ->andReturn('{"ok":true}');

// Or derive the return from the input:
$api->shouldReceive('echo')
    ->andReturnUsing(fn(string $in) => strtoupper($in));

Espiões: verifique depois do fato

Um espião inverte a ordem: aja primeiro e verifique depois. Mockery::spy() registra chamadas; depois, você as consulta com shouldHaveReceived(). Os espiões mantêm limpa a estrutura Preparar-Agir-Verificar quando você não quer que expectativas predefinidas deixem a configuração confusa.

<?php
use Mockery;

$logger = Mockery::spy(Logger::class);

$service = new PaymentService($logger);
$service->charge(500);

// Assertions happen AFTER the action:
$logger->shouldHaveReceived('info')
       ->with(Mockery::pattern('/charged 500/'))
       ->once();

Mockery::close();

Simulações parciais

Às vezes, você quer um objeto real, mas com um método substituído — uma simulação parcial. O makePartial() do Mockery encaminha as chamadas para métodos reais, exceto aqueles para os quais você definiu expectativas. Use com moderação: a dependência excessiva de simulações parciais geralmente indica que uma classe está fazendo coisas demais.

<?php
use Mockery;

$report = Mockery::mock(Report::class)->makePartial();
// Only stub the slow/external method; the rest runs for real
$report->shouldReceive('fetchRawData')->andReturn(['a', 'b', 'c']);

// real summarize() runs, using the stubbed data
$summary = $report->summarize();

Não simule o que não é seu

Um princípio fundamental dos testes: evite simular diretamente classes de terceiros. As APIs delas podem mudar, e sua simulação pode se afastar silenciosamente da realidade. Em vez disso, envolva-as em uma interface própria e simule essa interface. A simulação então verifica seu contrato, e um teste de integração do adaptador verifica a vinculação real.

<?php
interface PaymentGateway {            // you own this
    public function charge(int $cents, string $token): string;
}

final class StripeGateway implements PaymentGateway {
    public function __construct(private \Stripe\StripeClient $client) {}
    public function charge(int $cents, string $token): string {
        return $this->client->paymentIntents->create([/* ... */])->id;
    }
}
// Tests mock PaymentGateway, never \Stripe\StripeClient directly.

Sempre feche e verifique as contagens

Dois procedimentos operacionais obrigatórios:

  • Chame Mockery::close() em tearDown() (ou use o MockeryPHPUnitIntegration) para que as expectativas sejam realmente verificadas e as variáveis globais sejam limpas.
  • Use contagens explícitas (once(), times(n), never()) — simulações vagas deixam erros passarem.
<?php
use PHPUnit\Framework\TestCase;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;

final class OrderServiceTest extends TestCase
{
    use MockeryPHPUnitIntegration; // auto-calls Mockery::close()

    public function test_does_not_refund_paid_orders(): void
    {
        $gw = \Mockery::mock(PaymentGateway::class);
        $gw->shouldReceive('refund')->never();
        // ... exercise SUT ...
    }
}

Expectativas ordenadas

Às vezes, a ordem das chamadas faz parte do contrato — você precisa chamar beginTransaction() antes de commit(). O ordered() do Mockery impõe a sequência e faz o teste falhar se as chamadas chegarem fora de ordem. Use-o somente quando a ordem realmente importar; especificar a ordem em excesso produz testes frágeis.

<?php
use Mockery;

$tx = Mockery::mock(Transaction::class);
$tx->shouldReceive('begin')->once()->ordered();
$tx->shouldReceive('commit')->once()->ordered();

$service = new TransferService($tx);
$service->run();

Mockery::close(); // fails if commit() happened before begin()

Verificação rápida

Dublê de retorno ou simulação — qual usar em cada caso?

Recapitulação

Você dominou os dublês do Mockery:

  • Dublês de retorno (allows) para consultas; simulações (expects) para comandos; espiões para verificações posteriores.
  • Comparadores de argumentos (type, on, capture) ajustam o rigor.
  • Sequências de retorno e andReturnUsing modelam colaboradores com estado ou dinâmicos.
  • Simulações parciais substituem métodos individuais; use-as com moderação.
  • Não simule o que não é seu — envolva terceiros em uma interface própria.
  • Sempre chame Mockery::close() e verifique contagens explícitas de chamadas.

Próximo: testes de integração e funcionais.

Perguntas Frequentes

A aula “Simulação e criação de dublês com Mockery” é grátis?

Sim — o texto completo de “Simulação e criação de dublês com Mockery” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de PHP Academy, atualize para CoddyKit PRO. O curso de PHP Academy inclui 4 aulas no total.

O que vou aprender em “Simulação e criação de dublês com Mockery”?

Isole unidades com dublês de teste flexíveis. Você pratica PHP Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar PHP Academy?

Nenhuma experiência prévia é necessária. PHP Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Simulação e criação de dublês com Mockery”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de PHP Academy?

Sim. Cada aula de PHP Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. O fluxo de trabalho do desenvolvimento orientado por testes
  2. Simulação e criação de dublês com Mockery
  3. Testes de integração e funcionais
  4. Testes de mutação com Infection
← Voltar para PHP Academy