5 sinais de que você está fazendo continuous testing da maneira errada!

Suponhamos que você adotou uma série de práticas de Agile e DevOps para acelerar o lançamento de produtos e serviços no mercado, colocando o quanto antes novos recursos nas mãos dos seus clientes. Você criou uma série de práticas envolvendo continuous testing, porém, está enfrentando o desafio da escalabilidade, que envolve implementar a automação de testes em todos os níveis do sistema para bases de código. Isso, naturalmente, envolve muitos times de desenvolvedores e outros profissionais que realizam testes. E, para adicionar ainda mais complexidade nessa história, você precisa oferecer o devido suporte para inúmeros usuários, tanto aqueles que utilizam dispositivos móveis, quanto sistemas operacionais.

Mesmo com muito comprometimento e investimento em recursos, o resultado provavelmente será um conjunto de continuous testing que geram um alto custo de manutenção e um longo tempo de execução. E, pior, sua equipe não acredita nesse sistema!

Você se identificou com esse cenário? Então, aqui estão cinco erros comuns nos continuous testing e como mitigá-los utilizando ferramentas de open source. Confira!

1. Não trabalhar a comunicação dentro das equipes

Em projetos de TI de médio e grande porte com dezenas ou centenas de profissionais envolvidos, o que transforma os continuous testing em algo caro ou insustentável é manter as equipes de teste separadas das equipes de desenvolvimento.

Isso também ocorre em organizações que seguem práticas de Agile, nas quais analistas, desenvolvedores e testadores, trabalham juntos em critérios de aceitação de recursos e casos de testes. Nessas organizações, em geral, os continuous testing costumam ser parcialmente ou totalmente gerenciados por profissionais de fora do time, o que acaba sendo ineficiente justamente pela falta de comunicação.

O problema ainda se agrava quando as equipes trabalham em locais diferentes, o que dificulta ainda mais a comunicação.

Além disso, quando os continuous testing são automatizados sem a participação do desenvolvedor, eles tendem a se acoplar à interface do usuário tornando-os frágeis. A maioria dos testadores não tem insights sobre o design subjacente da UI (“user interface”) e não possuem habilidades para criar camadas de abstração ou executar testes de aceitação através de uma API pública (“application programming interface”).

Uma sugestão simples é dividir as equipes de automação em um silo e incluir engenheiros de teste diretamente nas equipes onde a discussão e a implementação dos recursos acontecem. Isso faz com que os impactos nos scripts de teste sejam descobertos e corrigidos imediatamente.

O ideal, no entanto, é tornar toda a equipe responsável por testes automatizados. Os proprietários de produtos, desenvolvedores e testadores devem trabalhar juntos para refinar os critérios de aceitação de recursos, criando cases de teste e priorizando estes cases para automação.

2. Realizar testes na interface do usuário

Você já deve saber que os testes automatizados realizados na interface do usuário são frágeis. Pequenas alterações podem interromper imediatamente todos os testes referentes a um determinado elemento GUI alterado. Esse é um dos principais motivos pelos quais as partes interessadas em técnicas / negócios percebem que os testes automatizados são caros para serem mantidos. Ferramentas de gravação e reprodução, como o SeleniumRecorder, usadas para gerar testes automáticos de GUI, são fortemente acopladas à GUI e, portanto, frágeis. Essas ferramentas podem ser usadas no primeiro estágio da criação de um teste automático, mas um segundo estágio de otimização é necessário para fornecer uma camada de abstração. Afinal, isso irá reduzir o acoplamento entre os testes de aceitação e a GUI do sistema em teste. Padrões de design, como PageObject, podem ser usados para essa finalidade.

No entanto, se a sua estratégia de teste automatizado estiver focada apenas em interfaces de usuário, ela pode contar com falhas rapidamente, já que exige muitos recursos e leva muito tempo para ser executada e geralmente é difícil de corrigir. De fato, a resolução da falha do teste da interface do usuário pode exigir que você passe por todos os níveis do sistema para descobrir a causa central do problema.

Uma abordagem melhor é priorizar o desenvolvimento de testes automatizados no nível certo para equilibrar os custos de manutenção deles ao tentar descobrir bugs nos estágios iniciais do pipeline de implantação de software (um padrão de chave introduzido na entrega contínua).

Como sugerido pela Pirâmide de Teste Agile, a grande maioria dos testes automatizados deve ser composta por testes de unidade (nível back-end e front-end). A propriedade mais importante dos testes unitários é que eles devem ser muito rápidos para executar (por exemplo, 5 a 10 minutos).

A camada de serviço (ou testes de componente) permite testar a lógica de negócios na API ou no nível de serviço, onde você não está sobrecarregando a interface do usuário (UI). Quanto mais alto o nível, mais lentos e mais frágeis os testes se tornam.

Normalmente, os testes de unidade são executados em cada consolidação do desenvolvedor e o processo de construção é interrompido em caso de falha de teste ou se a cobertura de teste estiver abaixo de um limite predefinido (por exemplo, quando menos de 80% das linhas de código são cobertas por testes de unidade). Depois que a compilação passa, ela é implantada em um ambiente de estágio e os testes de aceitação são executados. Qualquer build que passe nos testes de aceitação é então disponibilizado para testes manuais e de integração.

Os testes de unidade são uma parte essencial de qualquer estratégia de teste automatizado, mas geralmente não fornecem um nível suficientemente alto de confiança para que o aplicativo possa ser liberado. O objetivo dos testes de aceitação em nível de serviço e interface do usuário é provar que seu aplicativo faz o que o cliente quer, e não que ele funcione da maneira que seus programadores acham que deveria. Testes de unidade podem, às vezes, compartilhar essa ideia, mas nem sempre.

Para garantir que o aplicativo forneça valor aos usuários finais ao mesmo tempo em que equilibra os custos e o valor do conjunto de testes, você deve automatizar os testes de aceitação de serviço / componente e de IU com a Pirâmide de Teste Agile em mente.

Para saber mais sobre esses tipos de testes, níveis e ferramentas vale a pena conferir este artigo da ThoughtWorks.

3. Integrar sistemas muito cedo no pipeline de implementação

A integração com sistemas externos é uma fonte comum de problemas e pode ser algo difícil de corrigir. Por isso, é importante testar os pontos de integração com atenção.

Uma boa dica é não incluir os sistemas externos no escopo do teste de aceitação automatizado, pois isso fará com que você tenha menos controle sobre o sistema. É difícil definir um estado inicial do sistema externo e isso, por sua vez, terminará em uma execução de teste imprevisível, que falha na maioria das vezes, e você gastará boa parte do tempo **discutindo como corrigir falhas de teste com provedores externos.

O objetivo dos desenvolvedores com testes recorrentes é encontrar problemas o mais cedo possível e, para chegar até isso, o ideal é integrar o sistema continuamente. Ter conjuntos de testes em torno de cada ponto de integração, que são executados em um ambiente que tenha conexões reais com sistemas externos é valioso, porém, os testes devem ser mínimos e focados nos riscos do negócio para cobrir as principais etapas da jornada do cliente.

Também é recomendado criar duplas de teste que representam a conexão com todos os sistemas externos, usando-as em ambientes de desenvolvimento e/ou de estágio inicial, para que seus conjuntos de testes sejam mais rápidos e os resultados mais assertivos.

Para quem não conhece a ideia de “duplas de teste”, mas já ouviu falar sobre “mocks” e “stubs”, vale a pena dar uma lida nesse artigo aqui (em inglês) do blog de Martin Fowler.

No livro “Entrega Contínua: Releases de Software Confiáveis através da Automação de Construção,Teste e Implantação”, Jez Humble e David Farley aconselham que os testes de duplicação sejam realizados sempre para eliminar parte de um sistema externo quando:

  • O sistema externo está em desenvolvimento, mas a interface foi definida com antecedência (nessas situações, prepare-se para a interface mudar).

  • O sistema externo já é desenvolvido, mas você não tem uma instância de teste desse sistema disponível, ou ainda, o sistema de teste é muito lento ou com bugs para atuar como um serviço para execuções de teste automatizados regulares.

  • O sistema de teste existe, mas as respostas não são determinantes e, portanto, tornam a validação dos resultados impossíveis para os testes automatizados (por exemplo, um feed do mercado de ações).

  • O sistema externo assume a forma de outro aplicativo que é difícil de instalar ou requer intervenção manual por meio de uma interface do usuário.

  • A carga que seu sistema de integração automatizado demanda e o nível de serviço que ele exige sobrecarrega o ambiente de teste, que é configurado para lidar apenas com algumas interações exploratórias manuais.

Suponha que você precise integrar um ou mais sistemas externos que estão em desenvolvimento ativo, por exemplo. Provavelmente haverá mudanças nos esquemas, contratos e assim por diante. Tal cenário requer testes cuidadosos e regulares para identificar pontos nos quais equipes diferentes interagem. Esse é o caso das arquiteturas baseadas em micros serviços, que envolvem vários sistemas independentes implementados para testar uma única funcionalidade. Nesse contexto, revise as estratégias gerais de testes automatizados em favor de uma abordagem mais escalonável e sustentável, como a usada em contratos voltados ao consumidor, por exemplo.

Já, se você não está em tal situação, as seguintes ferramentas de software livre podem ser úteis para implementar duplas de teste a partir de uma especificação de contrato AP:

  • SoapUI mocking services: “Mocking”, do inglês, quer dizer “zombar” e de fato essa ferramenta acaba zombando tanto do SOAP quanto dos serviços de descanso.

  • WireMock: Pode simular serviços de descanso apenas.

  • Para serviços de descanso, as ferramentas OpenAPI para “mock services”, são capazes de gerar “stubs” de teste a partir da especificação do contrato OpenAPI.

4. Não avaliar a incompatibilidade de ferramentas de teste e desenvolvimento

Uma das consequências da transferência do trabalho de automação de teste para equipes diferentes da equipe de desenvolvimento é que isso cria uma divergência entre as ferramentas de desenvolvimento e de teste. Isso dificulta a colaboração e a comunicação entre os desenvolvedores e o time de teste, aumentando o custo geral da automação, além de promover práticas inadequadas, como ter a versão dos scripts de teste e o código de recurso não alinhados, por exemplo.

É muito comum encontrar equipes utilizando ferramentas de teste automatizadas de interface do usuário / API que são caras, porém, que tem pouca integração com sistemas de controle de versão padrão como o Git. Outras ferramentas, especialmente as comerciais baseadas em GUI, com recursos de fluxo de trabalho visual, criam uma falsa expectativa - principalmente entre os gerentes de teste - de que você pode facilmente esperar que os testadores desenvolvam testes automatizados que podem ser mantidos e reutilizados. Mesmo que isso seja possível, eles não podem dimensionar seu conjunto de testes automatizado com o tempo; os testes devem ter curadoria tanto quanto o código de recurso, que exige habilidades de programação em nível de desenvolvedor e práticas recomendadas.

Existem várias ferramentas de software livre que ajudam você a escrever testes de aceitação automatizados, bem como, reutilizar as habilidades das equipes de desenvolvimento. Se sua principal linguagem de desenvolvimento for Java ou JavaScript, você poderá achar úteis as seguintes opções:

- Java

  • Cucumber-jvm para implementar especificações executáveis ​​em Java para teste automatizado de interface do usuário e API

  • REST garantido para testes de API

  • SeleniumHQ para testes na web

  • Localizadores ngWebDriver para o Selenium WebDriver. Ele é otimizado para aplicativos da Web criados com Angular.js 1.x ou Angular 2+

  • Appium Java para testes móveis usando o Selenium WebDriver

- Java Script

-Cucumber.js é o mesmo que o Cucumber.jvm, mas é executado na plataforma Node.js

  • Chakram para teste de API

  • Protractor para teste da web otimizado para aplicativos da Web criados com AngularJS 1.x ou Angular 2+

  • Appium para testes móveis na plataforma Node.js

5. Não automatizar o gerenciamento de dados de teste

Para criar conjuntos detestes sustentáveis, é essencial ter uma estratégia eficaz tanto para criar quanto para manter os dados de teste. Ele exige a migração automática do esquema de dados e a inicialização dos dados de teste.

É tentador usar grandes “lixões” de banco de dados para testes automatizados, mas isso dificulta a versão e acaba aumentando o tempo geral de execução do teste. Uma abordagem melhor é capturar todas as alterações de dados nos scripts DDL e DML, que podem criar versões facilmente, além de executar de maneira mais simples o sistema de gerenciamento de dados. Esses scripts devem primeiro criar a estrutura do banco de dados e, em seguida, preencher as tabela com todos os dados de referência, necessários para o aplicativo ser iniciado. Além disso, você precisa projetar seus scripts de forma adicional para poder migrar seu banco de dados sem criá-lo do zero a cada vez e, o mais importante, sem perder dados valiosos.

As ferramentas de código aberto, como o Flyway, podem ajudá-lo a alinhar a execução de seus scripts DDL e DML com base em uma tabela no banco de dados que contém seu número de versão atual. No mento da implementação, o Flyway verifica a versão do banco de dados atualmente implantado e a versão do banco de dados exigida pela versão do aplicativo que está sendo implementado. Em seguida, ele trabalha com quais scripts executar para migrar o banco de dados de sua versão atual para a versão necessária e os executa no banco de dados em ordem.

Uma característica importante do seu conjunto de testes de aceitação automatizada, que o torna escalonável ao longo do tempo, é o nível de isolamento dos dados de teste: os dados de teste devem estar visíveis apenas para esse teste. Em outras palavras, um teste não deve depender do resultado dos outros testes para estabelecer seu estado, e outros testes não devem afetar seu sucesso ou falha de forma alguma. Ao isolar os testes uns dos outros, eles podem ser executados em paralelo para otimizar o desempenho do conjunto de testes, e mais fáceis de manter, já que você não precisa executar testes em uma ordem específica.

Ao considerar como configurar o estado do aplicativo para um teste de aceitação, Jez Humble e David Farley observam em seu livro que é útil distinguir entre três tipos de dados:

  • Dados de referência de teste: são os dados relevantes para um teste, mas que têm pouca influência sobre o comportamento em teste. Esses dados são normalmente lidos por scripts de teste e não são afetados pela operação dos testes. Eles podem ser gerenciados usando dados iniciais pré-preenchidos que são reutilizados em uma variedade de testes para estabelecer o ambiente geral.

  • Dados específicos do teste: esses são os dados que orientam o comportamento em teste. Também inclui dados transacionais criados e/ou atualizados durante a execução do teste. Ele deve ser exclusivos e usar estratégias de isolamento de teste para garantir que o teste inicie em um ambiente bem definido que não seja afetado por outros testes. Exemplos de práticas de isolamento de teste são a exclusão de dados específicos de teste e dados transacionais no final da execução do teste ou o uso de uma estratégia de particionamento funcional.

  • Dados de referência do aplicativo: esses dados são irrelevantes para o teste, mas são exigidos pelo aplicativo para inicialização. Dados de referência de aplicativo e dados de referência de teste podem ser mantidos na forma de scripts de banco de dados, onde são criadas novas versões e, em seguida, sofrem uma migração como parte da configuração inicial do aplicativo. Para dados específicos de teste, você deve usar APIs de aplicativo para que o sistema seja sempre colocado em um estado consistente como consequência da execução da lógica de negócios (que seria ignorada se você carregasse dados de teste diretamente no banco de dados usando scripts).

As equipes de Agile e DevOps continuam aquém dos testes de continuidade - um elemento crucial do pipeline de CI / CD. Mesmo como um único processo, o teste contínuo é composto de vários componentes que devem funcionar de forma alinhada. A estrutura da equipe, a priorização dos testes, os dados de teste e as ferramentas desempenham um papel fundamental no sucesso dos testes de continuidade. As equipes ágeis e de DevOps precisam ter todas as peças certas para ver os benefícios.

Agora que você já conhece os principais erros de quem faz testes de continuidade, confira também como usar o Testsigma para Agile e DevOps!