Posted on: September 05, 2025 10:08 AM
Posted by: Renato
Views: 213
Testando Logs em Aplicações Laravel com Log::shouldReceive() e Mockery
Testando Logs em Aplicações Laravel com Log::shouldReceive() e Mockery
Quando trabalhamos com testes unitários em aplicações Laravel, muitas vezes precisamos validar não apenas o retorno de métodos, mas também se determinadas ações ocorreram internamente. Um caso comum é verificar se mensagens de log foram geradas corretamente.
Por padrão, o Laravel utiliza o Monolog como biblioteca de logging, acessível através da facade Log. Em testes, no entanto, não é interessante que mensagens sejam gravadas em arquivos, enviadas para serviços externos ou até mesmo exibidas no console. Para evitar esses efeitos colaterais, podemos usar o poder do Mockery em conjunto com o método Log::shouldReceive().
O que é o Log::shouldReceive()?
O método shouldReceive() é utilizado para mockar (simular) a facade Log. Isso significa que, durante a execução dos testes, podemos substituir o comportamento real do log por uma versão controlada, permitindo:
-
Definir expectativas sobre quais métodos do log serão chamados.
-
Controlar quantas vezes esses métodos devem ser invocados.
-
Especificar quais parâmetros devem ser recebidos.
-
Evitar gravações reais em arquivos ou chamadas a serviços externos.
Em resumo, Log::shouldReceive() nos dá controle total sobre a interação com o sistema de logs em ambiente de teste.
Como funciona o Mockery nesse contexto?
O Mockery é a biblioteca utilizada pelo Laravel para criação de mocks e stubs. Com ele, conseguimos definir expectativas precisas de chamadas a métodos.
Ao usar Log::shouldReceive(), estamos na verdade configurando o comportamento esperado da facade Log por meio do Mockery.
Definindo Expectativas com shouldReceive()
A seguir, algumas formas comuns de definir expectativas sobre o uso do log:
1. Definindo o método esperado
Log::shouldReceive('error');
Aqui dizemos que esperamos que o método error() seja chamado.
2. Definindo a quantidade de chamadas
Log::shouldReceive('info')->once();Log::shouldReceive('warning')->times(2);Log::shouldReceive('debug')->zeroOrMoreTimes();
-
once()→ deve ser chamado exatamente uma vez. -
times(2)→ deve ser chamado exatamente duas vezes. -
zeroOrMoreTimes()→ pode ser chamado qualquer número de vezes (inclusive nenhuma).
3. Validando argumentos
Log::shouldReceive('error')->once()->with('Erro crítico detectado', ['user_id' => 123]);
Aqui estamos dizendo que:
-
O método
error()deve ser chamado uma vez. -
Ele deve receber exatamente a mensagem
"Erro crítico detectado"e o contexto['user_id' => 123].
Se o método for chamado com outros argumentos, o teste falhará.
4. Definindo retorno (caso necessário)
Normalmente, métodos de log retornam void, mas ainda é possível simular retornos se o código depender disso:
Log::shouldReceive('info')->andReturn(true);
Exemplo Prático
Suponha que temos um serviço que executa uma operação e, em caso de falha, registra um erro no log:
class MyService{public function doSomethingWithError(){// Lógica qualquer...Log::error('An error occurred', ['context' => 'value']);}}
Agora, queremos garantir que essa mensagem de erro seja registrada quando o método for chamado. Nosso teste ficaria assim:
use Illuminate\Support\Facades\Log;class MyTest extends TestCase{public function testSomethingLogsAnError(){Log::shouldReceive('error')->once()->with('An error occurred', ['context' => 'value']);$this->myService->doSomethingWithError();}}
Se a mensagem de log não for disparada corretamente, o teste falhará.
Benefícios de usar Log::shouldReceive()
-
Testes sem efeitos colaterais
Evita gravação de arquivos ou chamadas externas durante a execução dos testes. -
Assertividade
Garante que mensagens de log sejam emitidas corretamente, no formato e quantidade esperados. -
Isolamento
Permite testar apenas a lógica de geração de logs, sem depender da implementação do Monolog ou da configuração de logging da aplicação. -
Integração com Mockery
Oferece flexibilidade para criar mocks complexos e cenários de teste realistas.
Boas Práticas
-
Use
Log::shouldReceive()apenas em testes unitários, não em testes de integração. -
Sempre especifique a quantidade de chamadas (
once(),times(n)) para evitar falsos positivos. -
Valide os argumentos esperados com
with()ouwithArgs()para garantir que a mensagem de log está correta. -
Mantenha os testes focados: não valide logs irrelevantes para o caso de teste.
Conclusão
O uso de Log::shouldReceive() em testes unitários no Laravel é uma forma poderosa de garantir que sua aplicação está registrando logs da maneira correta, sem efeitos colaterais e com assertividade. Ele faz parte do arsenal de boas práticas para escrever testes robustos, aproveitando a flexibilidade da biblioteca Mockery.
Se a sua aplicação depende fortemente de logs para auditoria, monitoramento ou depuração, testar o comportamento dos logs é tão importante quanto testar retornos de métodos.
Donate to Site
Renato
Developer