Nossa divisão cria tubulações totalmente automáticas para gerar novas versões de aplicativos no ambiente de produção. Obviamente, isso requer testes funcionais automatizados. Sob o corte - a história de como, começando com o teste em um thread na máquina local, chegamos ao lançamento multithread de autoteste no Selenoid no pipeline de montagem com o relatório Allure nas páginas do GitLab e, como resultado, obtivemos uma ferramenta de automação interessante que os futuros podem usar equipes.

Por onde começamos
Para implementar autotestes e integrá-los ao pipeline, precisávamos de uma estrutura de automação, que pudesse ser alterada de forma flexível para atender às nossas necessidades. Idealmente, eu queria obter um padrão único para o mecanismo de autoteste, adaptado para incorporar autotestes em um pipeline. Para implementação, escolhemos as seguintes tecnologias:
- Java
- Maven
- Selênio
- Pepino + 4 de junho,
- Allure
- Gitlab

Por que esse conjunto? Java é uma das linguagens mais populares para autotestes, além disso, todos os membros da equipe falam. Selênio é a solução óbvia. O pepino, entre outras coisas, deveria aumentar a confiança nos resultados dos autotestes pelas unidades envolvidas nos testes manuais.
Testes de rosca única
Para não reinventar a roda, pegamos a experiência de vários repositórios no GitHub como base da estrutura e os adaptamos para nós mesmos. Criamos um repositório para a biblioteca principal com o núcleo da estrutura de autoteste e um repositório com um exemplo Gold de implementação de autotestes em nosso núcleo. Cada equipe teve que tirar uma imagem de ouro e desenvolver testes nela, adaptando-a ao seu projeto. Nós implantamos no banco GitLab-CI, no qual configuramos:
- execuções diárias de todos os autotestes escritos para cada projeto;
- lançamentos no pipeline de montagem.
No início, havia poucos testes, e eles foram em um fluxo. O lançamento de thread único no GitLab Windows-runner foi bastante satisfatório para nós: os testes carregaram um pouco a bancada e quase não utilizaram recursos.
Com o tempo, os autotestes se tornaram cada vez mais, e pensamos em executá-los em paralelo, quando uma corrida completa começou a levar cerca de três horas. Houve outros problemas:
- não podíamos garantir que os testes fossem estáveis;
- os testes que passaram por várias execuções consecutivas na máquina local às vezes caíam no CI.
Exemplo de configuração de autoteste:
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.20</version> <configuration> <skipTests>${skipTests}</skipTests> <testFailureIgnore>false</testFailureIgnore> <argLine> -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" -Dcucumber.options="--tags ${TAGS} --plugin io.qameta.allure.cucumber2jvm.AllureCucumber2Jvm --plugin pretty" </argLine> </configuration> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency> </dependencies> </plugin> <plugin> <groupId>io.qameta.allure</groupId> <artifactId>allure-maven</artifactId> <version>2.9</version> </plugin> </plugins>
Exemplo de relatório de fascínio
Carga do corredor durante os testes (8 núcleos, 8 GB de RAM, 1 thread)Vantagens de testes single-threaded:
- fácil de configurar e executar;
- Os lançamentos no CI praticamente não diferem dos lançamentos locais;
- testes não se afetam;
- requisitos mínimos de recursos do corredor.
Contras de testes single-threaded:
- muito longo prazo;
- longa estabilização de testes;
- uso ineficiente dos recursos do corredor, utilização extremamente baixa.
Testes de forquilha JVM
Como não nos importamos com código seguro para threads ao implementar a estrutura básica, o
plugin pepino-jvm-paralelo para o Maven se tornou a maneira mais óbvia de executar em paralelo. O plug-in é fácil de configurar, mas para a operação paralela correta dos autotestes, você precisa executar em navegadores separados. Nada a fazer, eu tive que usar Selenoid.
O servidor Selenoid foi criado em uma máquina com 32 núcleos e 24 GB de RAM. O limite foi definido em 48 navegadores - 1,5 threads por núcleo e cerca de 400 MB de RAM. Como resultado, o tempo de teste foi reduzido de três horas para 40 minutos. Acelerar as execuções ajudou a resolver o problema de estabilização: agora podemos executar rapidamente novos autotestes de 20 a 30 vezes, até garantir que eles sejam executados de forma estável.
A primeira desvantagem da solução foi a alta utilização dos recursos do corredor com um pequeno número de encadeamentos paralelos: em 4 núcleos e 8 GB de RAM, os testes funcionaram de maneira estável em não mais que 6 encadeamentos. O segundo menos: o plug-in gera classes de corredor para cada cenário, não importa quantas são executadas.
Importante! Não jogue uma variável com tags em
argLine , por exemplo, assim:
<argLine>-Dcucumber.options="--tags ${TAGS} --plugin io.qameta.allure.cucumber2jvm.AllureCucumber2Jvm --plugin pretty"</argLine> … Mvn –DTAGS="@smoke"
Se você passar a tag dessa maneira, o plug-in irá gerar corredores para todos os testes, ou seja, tentar executar todos os testes, ignorando-os logo após o lançamento e criando muitos garfos da JVM.
É correto colocar a variável com a tag nas
tags nas configurações do plug-in, veja o exemplo abaixo. Outros métodos que testamos têm problemas ao conectar o plug-in Allure.
Exemplo de tempo de execução para 6 testes curtos com configurações incorretas:
[INFO] Total time: 03:17 min
Um exemplo de tempo de execução de teste se você passar diretamente a tag para
mvn ... –Dcucumber.options :
[INFO] Total time: 44.467 s
Exemplo de configuração de autoteste:
<profiles> <profile> <id>parallel</id> <build> <plugins> <plugin> <groupId>com.github.temyers</groupId> <artifactId>cucumber-jvm-parallel-plugin</artifactId> <version>5.0.0</version> <executions> <execution> <id>generateRunners</id> <phase>generate-test-sources</phase> <goals> <goal>generateRunners</goal> </goals> <configuration> <tags> <tag>${TAGS}</tag> </tags> <glue> <package>stepdefs</package> </glue> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.21.0</version> <configuration> <forkCount>12</forkCount> <reuseForks>false</reuseForks> <includes>**
Um exemplo de um relatório Allure (o teste mais instável, 4 reranas)
Carga do corredor durante os testes (8 núcleos, 8 GB de RAM, 12 threads)Prós:
- configuração simples - você só precisa adicionar o plugin;
- a capacidade de executar simultaneamente um grande número de testes;
- estabilização mais rápida dos testes, graças à reivindicação 1.
Contras:
- vários SO / contêineres necessários;
- alto consumo de recursos por bifurcação;
- O plug-in está obsoleto e não é mais suportado.
Como vencer a instabilidade
Os suportes de teste não são perfeitos, assim como os próprios testes automáticos. Não é de surpreender que tenhamos vários testes mal feitos. O
plug-in do maven surefire veio em
socorro , o qual,
pronto para uso , suporta o reinício de testes em queda. Você precisa atualizar a versão do plug-in para pelo menos 2,21 e escrever uma linha com o número de reinicializações no arquivo pom ou passar como argumento para o Maven.
Exemplo de configuração de autoteste:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.21.0</version> <configuration> …. <rerunFailingTestsCount>2</rerunFailingTestsCount> …. </configuration> </plugin>
Ou na inicialização:
mvn ... -Dsurefire.rerunFailingTestsCount = 2 ...Como alternativa, defina as opções do Maven para o script do PowerShell (PS1):
Set-Item Env:MAVEN_OPTS "-Dfile.encoding=UTF-8 -Dsurefire.rerunFailingTestsCount=2"
Prós:
- não há necessidade de perder tempo analisando um teste instável quando ele falha;
- Você pode atenuar os problemas de estabilidade da bancada de testes.
Contras:
- você pode pular defeitos flutuantes;
- o tempo de execução é aumentado.
Testes paralelos com a biblioteca Cucumber 4
O número de testes aumentou todos os dias. Pensamos novamente em acelerar as corridas. Além disso, eu queria integrar o maior número possível de testes ao conjunto de pipeline do aplicativo. Um fator crítico foi a geração muito longa de corredores ao executar em paralelo usando o plug-in Maven.
O pepino 4 já havia sido lançado naquele momento, então decidimos reescrever o kernel para esta versão. Nas notas de versão, prometemos um lançamento paralelo no nível do encadeamento. Teoricamente, isso deveria ter sido:
- acelere significativamente a execução de autotestes aumentando o número de threads;
- exclua a perda de tempo para gerar corredores para cada autoteste.
Otimizar a estrutura para autotestes multithread não foi tão difícil. O Pepino 4 executa cada teste individual em um encadeamento dedicado do início ao fim, portanto, algumas coisas estáticas comuns foram simplesmente convertidas em variáveis ThreadLocal.
A principal coisa ao converter com as ferramentas de refatoração do Idea é verificar os locais onde a variável foi comparada (por exemplo, verificando se há nulo). Além disso, você precisa renderizar o plug-in Allure nas anotações da classe Junit Runner.
Exemplo de configuração de autoteste:
<profile> <id>parallel</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.0.0-M3</version> <configuration> <useFile>false</useFile> <testFailureIgnore>false</testFailureIgnore> <parallel>methods</parallel> <threadCount>6</threadCount> <perCoreThreadCount>true</perCoreThreadCount> <argLine> -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" </argLine> </configuration> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency> </dependencies> </plugin> </plugins> </build> </profile>
Um exemplo de um relatório Allure (o teste mais instável, 5 reranos)
Carga do corredor durante os testes (8 núcleos, 8 GB de RAM, 24 threads)Prós:
- baixo consumo de recursos;
- suporte nativo do pepino - nenhuma ferramenta adicional necessária;
- a capacidade de executar mais de 6 threads no núcleo do processador.
Contras:
- você precisa garantir que o código suporte a execução multithread;
- limiar de entrada aumenta.
Relatórios de fascínio nas páginas do GitLab
Após a introdução do lançamento multithread, começamos a gastar muito mais tempo analisando relatórios. Naquele momento, tivemos que fazer upload de cada relatório como um artefato no GitLab, fazer o download e descompactá-lo. Não é muito conveniente e longo. E se alguém quiser ver o relatório em casa, precisará executar as mesmas operações. Queríamos obter feedback mais rapidamente e havia uma saída: as páginas do GitLab. Esse é um recurso interno que está disponível imediatamente em todas as versões recentes do GitLab. Permite implantar sites estáticos no servidor e acessá-los por um link direto.
Todas as capturas de tela com relatórios Allure foram feitas nas páginas do GitLab. O script para implantar o relatório nas páginas do GitLab é no Windows PowerShell (antes disso, você precisa executar autotestes):
New-Item -ItemType directory -Path $testresult\history | Out-Null try {Invoke-WebRequest -Uri $hst -OutFile $outputhst} Catch{echo "fail copy history"} try {Invoke-WebRequest -Uri $hsttrend -OutFile $outputhsttrnd} Catch{echo "fail copy history trend"} mvn allure:report #mvn assembly:single -PzipAllureReport xcopy $buildlocation\target\site\allure-maven-plugin\* $buildlocation\public /s /i /Y
Qual é o resultado
Portanto, se você estava pensando se precisa do código seguro de Thread na estrutura de autoteste do Cucumber, agora a resposta é óbvia - com o Cucumber 4 é fácil implementá-lo, aumentando significativamente o número de threads iniciados simultaneamente. Com esse método de execução de testes, a questão já é sobre o desempenho da máquina com o Selenoid e a bancada de testes.
A prática mostrou que a execução de testes automáticos em threads pode minimizar o consumo de recursos com o melhor desempenho. Como pode ser visto nos gráficos, um aumento de 2 vezes nos fluxos não leva a uma aceleração semelhante nos testes de desempenho. No entanto, conseguimos adicionar mais de 200 testes automáticos à montagem do aplicativo, que mesmo com 5 rerans podem ser concluídos em aproximadamente 24 minutos. Isso permite que você receba feedback rápido deles e, se necessário, faça alterações e repita o procedimento novamente.