O problema
Você já se encontrou na situação em que tinha que fazer um deploy ou subir sua atualização urgente e teve que ficar esperando os testes terminarem para finalizar pipeline? Nessa hora qualquer minuto é uma eternidade.
Eu estava enfrentando esse problema, meus testes demoravam cerca de 6 minutos para rodar e esse tempo seguia aumentando a cada nova feature entregue.
A solução
Para resolver isso encontrei o pacote Paratest, basicamente, esse pacote adiciona suporte a testes paralelos ao PHPUnit, fazendo com que seus testes rodem simultaneamente.
Instalação
Primeiro começamos instalando o pacote:
composer require --dev brianium/paratest
Após isso, sua aplicação já tem suporte aos testes em paralelo. 🥳
Para começar a usar vamos rodar o comando:
vendor/bin/paratest -p4 --runner=WrapperRunner
Opções usadas:
-p4
A opção
-p
é referente ao número de processos simultâneos que irão rodar os testes.--runner=WrapperRunner
Por padrão, o PHPUnit inicia um novo processo para cada arquivo de testes que irá rodar, utilizando o
--runner=WrapperRunner
cada processo-p
irá iniciar apenas uma vez e manter tudo o que é preciso para rodar todos os arquivos de testes.Para saber todas as opções disponíveis e ter mais detalhes sobre as usadas aqui, acesse a documentação do pacote.
Resultados
Para efeitos de comparação vamos rodar modo sequencial, apenas com o PHPUnit e no modo paralelo, com o Paratest. Serão 646 testes com 75442 asserções, a maioria desses testes sendo de integração, com acesso ao banco de dados e outras dependências.
Testes Sequenciais:
O tempo levado pelo PHPUnit para rodar todos esses testes foi de aproximadamente 5 minutos e 39 segundos. Agora, lembre-se da situação em que você está esperando a pipeline terminar para finalmente fazer um deploy, esses quase 6 minutos se tornam uma eternidade.
Testes Paralelos:
Já o tempo levado pelo Paratest foi de aproximadamente 1 minuto e 11 segundos. Um tempo muito melhor para você que está ansioso esperando.
Nem tudo são flores 😓
Quando estamos trabalhando com paralelismo um grande problema é controlar o acesso de cada processo aos recursos e dados do sistema, e nesse caso não é diferente. Em testes que devem acessar o banco de dados, modificar e consultar registros pode ocorrer de dois testes acessarem o mesmo dado simultaneamente causando possíveis deadlocks no banco de dados e assim, também, um desses testes acabará falhando.
Uma possível solução para esses casos é o isolamento de cada teste no acesso ao banco de dados. É possível fazer isso rodando os testes dentro de uma transaction assim fazendo com que todos os registros modificados e/ou consultados estejam isolados e tudo que foi feito pelo teste é desconsiderado após seu término.
- O Laravel disponibiliza a Trait DatabaseTransactions, com ela no seu TestCase (classe na qual seus testes irão extender), seus testes irão por padrão rodar dentro de uma transaction.
- Caso use SQLServer, outra possível solução é habilitar a opção READ_COMMITTED_SNAPSHOT, ela ajuda com esses casos de dados sendo acessados e modificados simultanemente. Para mais detalhes acesse: https://www.mssqltips.com/sqlservertip/6368/sql-server-readcommittedsnapshot-database-option-and-read-commited-transaction-isolation-level/
- Observação: no meu caso as duas opções foram usadas.
Conclusão
Com a necessidade de cobrir sua aplicação com testes aumentando a cada dia, rapidamente você começa a se sentir incomodado com a demora na finalização dos testes. Para ajudar nesse ponto, a opção de rodar seus testes em paralelo é muito bem vinda, ela está aí para aumentar a performance e produtividade do seu time nos deploys e no dia a dia.
Se você ainda não usou, deveria dar uma chance e ver o tempo que você está perdendo (literalmente rs).
Top comments (2)
Muito TOOOP! Parabéns!!!
Valeu André! 👍 😁