микрозаймы онлайн займы на карту займы по паспорту

Como utilizar Mocks nas Facades do Laravel 3

Vejo em muitos blogs de desenvolvimento, críticas às vezes pesadas em relação à testabilidade em aplicações com o Laravel, então tentei elucidar alguns dos pontos que acredito estarem obscuros para estes desenvolvedores. Para tanto, levo em consideração que o leitor tenha conhecimento de:

  • Testes Unitários
  • Dependecy Injection
  • Mocks

Desenvolvedores que estão começando com o Laravel muitas vezes têm a impressão de que estão lidando com um framework que não facilita nem incentiva a criação de testes no desenvolvimento de aplicações. A principal justificativa para tal fato são as famosas “chamadas estáticas para tudo” que o Laravel provê e, se tratando de uma linguagem como o PHP, na qual Dependency Injection é uma ótima alternativa para a criação de um código mais testável, a conclusão é a de que este não é um framework apropriado em termos de testabilidade, por não facilitar a utilização de Mocks ou Stubs.

Em primeiro lugar, é preciso que se entenda que as chamadas estáticas do Laravel não são apenas funções espalhadas em classes e sim Facades. Mas o que são Facades ? Uma Facade é um Design Pattern que tem como finalidade prover uma interface simples do ponto de vista do código que a utiliza (código cliente) para uma estrutura complexa de objetos relacionados. De fato, se pesquisarmos no core do Laravel, veremos que cada uma das Facades existentes apenas facilitam o acesso à uma estrutura de objetos complexa, com um design orientado à objetos muito bem feito, que utiliza Dependency Injection e é muito bem testada, inclusive com Mocks.

Voltando ao plano do desenvolvedor que utiliza o Framework, você pode estar se perguntando: “Mas qual a solução ? Tento encontrar as classes que a Facade referencia e injetá-las via DI na classe que irá utilizá-la, afim de utilizar Mocks destas em testes ?”. Só a idéia já parece um tanto quanto complicada e a resposta é: felizmente não. Pensando justamente neste detalhe, o Laravel 4 provê uma facilidade para se criar Mocks de Facades diretamente da própria chamada da Facade. Vamos levar em consideração o exemplo abaixo:

public function signUpUser()
{
  // Rotina para criar usuários....

  // E populamos uma fila para mandar email ao usuário cadastrado
  Queue::push('SendEmail', ['message' => 'Criado com sucesso !']);

  return 'All done!';
}

Partindo do princípio que testes unitários devem testar a menor unidade lógica de uma aplicação, sem depender de unidades externas à ela, concluímos que devemos criar um Mock da Facade Queue utilizada pelo método signUpUser(), uma vez que apenas queremos testar a criação de usuários e não depender da fila de envio de emails. Imagine o teste enviando emails para usuários inexistentes. De fato, não faz sentido. Neste ponto é que mora a dúvida. Como “Mockear” a Facade ?

No Laravel 4, todas as Facades tem agora acesso ao método shouldReceive, que retorna uma instância de um objeto Mockery. Mockery é um Framework para a criação de Mocks em PHP muito robusto e eloquente, sendo uma ótima alternativa aos Mocks nativos do PHPUnit. O teste do exemplo acima fica então da seguinte maneira:

public function testSignUpUser()
{
    // Esperamos que a Facade Queue receba uma chamada para o método push() uma vez,
   // com ['message' => 'Criado com sucesso !'] como parâmetro

  Queue::shouldReceive('push')->once()->with(['message' => 'Criado com sucesso !']);

  $myAuthInstance->signUpUser();
}

Desta forma, conseguimos programar expectativas para a Facade utilizada no método sem que a verdadeira seja utilizada. Isto remove a dependência de unidades e cria um teste totalmente desacoplado. No caso do exemplo, a fila não será executada de verdade e nenhum email será disparado. O teste passará se o método push() da classe Queue for chamado uma vez com o array [‘message’ => ‘Criado com sucesso !’] como parâmetro.

Pense que a Facade poderia estar consultando um WebService. Se não utilizássemos o Mock, poderíamos criar um dos piores “smells” em testes unitários que é a consulta à servidores externos no teste. Em termos performáticos não precisamos nem citar o problema. Em termos de inconsistência, pense que o servidor do WebService, que não é de responsabilidade do desenvolvedor criador do teste, pode cair e o teste pode falhar mesmo que o código que utiliza o serviço esteja correto o que acarretaria em um teste falso negativo.

Para se testar serviços externos ou mesmo a fila de envio de emails, deve-se criar testes de integração para os mesmos e normalmente separa-se as suítes de testes, mas este é um assunto para outro post =P

Por fim, acredito que esta forma de criar Mocks provida pelo Laravel é uma das mais claras e concisas que vi em um Framework PHP. É uma ótima feature para se tirar vantagem das ótimas e simples Facades do Framework e manter sua aplicação altamente testada, o que é obviamente, uma boa prática.

Test it ! =P

  • SalThaMasta

    Bem explicativo! Continue o bom trabalho.

  • fhferreira

    Vlw Brayan mais uma vez 😀

  • fabrizio

    parabéns pelo post.. é bom alguem falar sobre Testes.