Implementar, escalar: a experiência do uso de autotestes em VTB

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>**/*IT.class</includes>                  <testFailureIgnore>false</testFailureIgnore>                   <!--suppress UnresolvedMavenProperty -->                   <argLine> -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" -Dcucumber.options="--plugin io.qameta.allure.cucumber2jvm.AllureCucumber2Jvm TagPFAllureReporter --plugin pretty"                   </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, 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.

Source: https://habr.com/ru/post/pt473950/


All Articles