Tecnologia do DevOps: testes contínuos

O segredo para agregar qualidade a um software é agilizar o recebimento de feedback sobre o impacto das alterações durante o ciclo de vida da entrega de software. Tradicionalmente, as equipes confiam em testes manuais e inspeção de código para verificar a exatidão dos sistemas. Essas inspeções e testes normalmente ocorriam em uma fase separada após o "dev complete". Essa abordagem tem as seguintes desvantagens:

  • A execução manual do teste de regressão é demorada, economicamente onerosa e provoca um gargalo no processo. O software não pode ser lançado com frequência e os desenvolvedores não conseguem receber feedback com a rapidez necessária.
  • Testes e inspeções manuais não são confiáveis porque as pessoas têm baixo desempenho na execução de tarefas repetitivas, como testes de regressão manual. Além disso, é difícil prever, por meio de inspeção, o impacto das alterações em um sistema de software complexo.
  • Depois que o software estiver no estágio "dev complete", os desenvolvedores precisarão esperar muito tempo para receber feedback sobre as alterações. Isso geralmente resulta em um trabalho substancial para classificar defeitos e corrigi-los. Problemas de desempenho, segurança e confiabilidade geralmente exigem alterações de design que são ainda mais caras quando solucionadas nesta fase.
  • Ciclos de feedback longos também dificultam a criação de código de qualidade pelos desenvolvedores, e, sob pressão do cronograma, as equipes de desenvolvimento às vezes podem tratar a qualidade como "problema de outra pessoa".
  • Quando os desenvolvedores não são responsáveis por testar o próprio código, fica difícil aprender a escrever códigos testáveis.
  • Para sistemas que estão sempre em evolução, manter a documentação de teste atualizada exige um esforço significativo.

Em vez disso, as equipes podem:

  • executar todos os tipos de testes continuamente durante todo o ciclo de vida da entrega de software;
  • criar e selecionar conjuntos rápidos e confiáveis de testes automatizados que são executados como parte dos pipelines de entrega contínua (em inglês).

Esse processo não ajuda apenas as equipes a criar (e aprender a criar) software de alta qualidade mais rapidamente, a pesquisa da DORA mostra que também aumenta a estabilidade do software, reduz a exaustão da equipe e diminui a dificuldade de implantação.

Como implementar testes contínuos

Para criar qualidade no software, você precisa executar continuamente testes automatizados e manuais durante todo o processo de entrega para validar a funcionalidade e a arquitetura do sistema em desenvolvimento. Essa disciplina tem um componente organizacional e um componente técnico. Em nível organizacional, a pesquisa da DORA acredita que as equipes melhoram quando:

  • permitem que testadores trabalhem com desenvolvedores em todo o processo de desenvolvimento e entrega. Observe que "testador" é um papel, não necessariamente um emprego em tempo integral, mesmo que esse seja um padrão comum discutido abaixo;
  • realizam atividades de teste manuais, como testes exploratórios, testes de usabilidade e testes de aceitação, durante todo o processo de entrega.

Uma atividade técnica importante é criar e manter um conjunto de conjuntos de testes automatizados, incluindo os seguintes:

  • Testes de unidade: normalmente, eles testam um único método, classe ou função isoladamente, fornecendo garantias aos desenvolvedores de que o código opera conforme projetado. Para assegurar que o código possa ser testado e os testes possam receber manutenção, escreva os testes de unidade antes do código, uma técnica conhecida como desenvolvimento orientado a teste (link em inglês) ou TDD, na sigla em inglês.
  • Testes de aceitação: normalmente testam um aplicativo ou serviço em execução (em geral, com dependências substituídas por cópias de teste) para garantir que um nível mais alto de funcionalidade opere conforme projetado e que não tenham sido introduzidos erros de regressão (link em inglês). Exemplos de testes de aceitação podem verificar os critérios de aceitação da empresa para um histórico de usuário ou a correção de uma API. Escreva esses testes durante o processo de desenvolvimento. Ninguém pode declarar o trabalho de desenvolvimento como "dev complete" sem que os testes de aceitação automatizados tenham sido aprovados.

O diagrama a seguir, criado inicialmente por Brian Marick e depois mencionado no livro Agile Testing: A Practical Guide for Testers and Agile Teams, mostra os tipos de testes automáticos e manuais que precisam ser executados (links em inglês).

imagem

Os testes automatizados, destacados no diagrama anterior, se encaixam em um pipeline de implantação (em inglês) de entrega contínua. Nesse tipo de pipeline, cada alteração executa um build e cria pacotes de software, executa testes de unidade e possivelmente realiza outras verificações, como análise estática. Depois que esses pacotes passam pelo primeiro estágio, testes de aceitação automatizados mais abrangentes e, provavelmente, alguns testes não funcionais, como testes de desempenho e verificações de vulnerabilidade, são executados no software em execução implantado automaticamente. Qualquer build que for aprovado no estágio de aceitação é normalmente disponibilizado para exploração manual e testes de usabilidade. Por fim, se nenhum erro for encontrado nessas etapas manuais, o aplicativo será considerado como passível de lançamento.

A execução contínua de testes como parte de um pipeline contribui para um feedback rápido para os desenvolvedores, menor tempo de lead desde o check-in até o lançamento e baixa taxa de erros nos ambientes de produção. A maior parte do trabalho dos desenvolvedores é validada em minutos, em vez de dias ou semanas, por isso, eles podem corrigir os bugs o mais rápido possível.

O diagrama a seguir mostra um exemplo de um pipeline de implantação linear simples. Neste exemplo, a cor verde significa que nenhum problema foi encontrado, e vermelho significa que um ou mais problemas foram descobertos.

imagem

No padrão de pipeline de implantação, todas as alterações criam um candidato a versão e o ciclo de feedback rápido ajuda a detectar problemas no processo o mais cedo possível. Quando um pacote chega ao final do pipeline e a equipe ainda não se sente confortável para liberá-lo ou são descobertos defeitos já em produção, o pipeline precisa ser aprimorado, talvez com a adição ou atualização de testes.

Armadilhas comuns

  • Não envolver os desenvolvedores nos testes. A pesquisa do DORA mostra que, quando os desenvolvedores são responsáveis principalmente por criar e manter conjuntos de testes automatizados e quando é fácil para os desenvolvedores corrigirem falhas em testes de aceitação, o desempenho é aprimorado. Quando outros grupos são os proprietários da automatização de testes, geralmente surgem dois problemas:

    • O estado dos conjuntos de testes frequentemente é incompleto. Alterações no código podem exigir a atualização dos testes. Se os desenvolvedores não forem responsáveis pela automação dos testes, o pipeline do build permanecerá incompleto até que a equipe responsável corrija os testes.
    • Os desenvolvedores escrevem um código difícil de testar. Os desenvolvedores tendem a resolver o problema recebido sem pensar em como ele será testado. Isso pode levar à criação de códigos mal projetados e conjuntos de testes caros e difíceis de manter.

    Os testadores e as equipes de controle de qualidade continuam tendo um papel importante nesse modo de trabalhar. Os testadores têm uma perspectiva única do sistema, porque entendem como os usuários interagem com ele. É uma prática recomendada unir testadores a desenvolvedores para criar e desenvolver conjuntos de testes automatizados usando ferramentas de compartilhamento de tela, caso as equipes não estejam fisicamente no mesmo local. Assim, eles podem aprender uns com os outros e resolver problemas em tempo real. Os testadores também desempenham um papel essencial na realização de testes exploratórios e de usabilidade, além de ajudar a selecionar conjuntos de testes.

  • Falha ao selecionar seus conjuntos de testes. Sempre analise e melhore seus conjuntos de testes para encontrar problemas com facilidade e manter a complexidade e os custos sob controle. Exemplo:

    • Os conjuntos de testes de aceitação normalmente representam jornadas do usuário completas (em inglês) ao longo do sistema, em vez de apenas coleções de critérios de aceitação automatizados. À medida que seu produto evolui, esses cenários e os conjuntos de testes que os validam também evoluem. Para mais informações sobre esse processo, consulte o vídeo Como criar as bases para a automação de testes bem-sucedida, (em inglês) de Angie Jones.
    • Se toda vez que houver uma alteração de código, também for preciso alterar vários testes de unidade, provavelmente você está confiando demais na simulação (em inglês) ou falhando na remoção do seu conjunto de testes de unidade.
    • Mantenha seus conjuntos de testes bem fatorados. Se todas as alterações na interface do usuário fizerem com que vários testes de aceitação falhem, use o padrão de objeto de página (em inglês) para desacoplar seus testes do sistema que está sendo testado.
    • Caso a manutenção dos seus testes seja cara, isso pode indicar problemas com a arquitetura do seu software. Continue investindo para tornar seu software fácil de testar, incluindo a incorporação de refatoração (em inglês) no trabalho diário da equipe.
  • Ter a proporção incorreta de testes de unidade e aceitação. Um objetivo específico do projeto de um conjunto de testes automatizados é encontrar erros o mais cedo possível. É por isso que os testes unitários de execução mais rápida são feitos antes dos testes de aceitação de execução mais lenta, sendo ambos executados antes de qualquer teste manual.

    Use a categoria mais rápida de testes para encontrar erros. Quando encontrar um erro em um teste de aceitação ou durante um teste exploratório, adicione um teste de unidade para garantir que esse erro seja detectado mais rápido, mais cedo e de maneira mais econômica na próxima vez. Mike Cohn descreveu a pirâmide de automatização de teste ideal (em inglês), mostrada no diagrama a seguir, em que a maioria dos erros é detectada usando o teste de unidade.

    imagem

  • Tolerar testes não confiáveis. Os testes precisam ser confiáveis: ou seja, quando os testes são aprovados, precisamos ter certeza de que o software está pronto para ser lançado e que as falhas dos testes indicam um defeito real. Especificamente, não toleram testes instáveis. Leia sobre a estratégia do Google para mitigação de testes instáveis (em inglês).

Formas de melhorar o teste contínuo

Se sua organização ainda não tem uma cultura de teste de unidade por desenvolvedores, não se preocupe. O teste de unidade não era uma prática difundida nos primeiros anos do Google. A cultura atual de testes de unidade abrangentes foi impulsionada por um grupo de voluntários no Google, chamado Grupo de Testes. Leia como eles ajudaram a conduzir a adoção de testes de unidade (em inglês) criando uma comunidade de práticas focadas na propagação de conhecimento sobre o testes no Google e convencendo os desenvolvedores a respeito do valor do teste de unidade.

Se você não dispuser de automação de testes suficiente, comece criando um pipeline de implantação estrutural. Por exemplo, primeiro crie um único teste de unidade, um único teste de aceitação e um script de implantação automatizado que sustente um ambiente de teste exploratório e depois os agrupe. Aumente gradualmente a cobertura de teste e amplie o pipeline de implantação de acordo com a evolução do seu produto ou serviço.

Se você já estiver trabalhando em um sistema já em execução, siga as orientações deste artigo, mas não interrompa a atividade para atualizar um conjunto abrangente de testes automatizados. Em vez disso, crie uma pequena quantidade de testes de aceitação para a funcionalidade de alto valor. Em seguida, verifique se está sendo exigido que os desenvolvedores gravem testes de unidade e aceitação para qualquer nova funcionalidade e qualquer funcionalidade que você estiver alterando. Pense em usar o TDD para melhorar a qualidade e a manutenção, tanto do código principal quanto do código de teste e garanta que, quando seus testes de aceitação falharem, você criará testes de unidade para descobrir mais o defeito com mais rapidez futuramente.

Se você tiver um conjunto de testes de manutenção oneroso e pouco confiável, não hesite em abandoná-lo. Um conjunto de dez testes confiáveis, rápidos e incontestáveis é muito melhor que um conjunto de centenas de testes de manutenção difícil e em que ninguém confia.

Formas de avaliar testes contínuos

É possível medir os resultados dos testes contínuos no seu ambiente fazendo o seguinte:

Fator a testar O que medir Meta
Criadores de testes de aceitação e de unidade. Porcentagem de testes criados por desenvolvedores, testadores e qualquer outro grupo da empresa. Os principais autores e mantenedores de testes de aceitação são desenvolvedores.
Número de bugs encontrados em testes de aceitação, testes exploratórios e na produção. Alteração na proporção de erros encontrados ao longo do tempo. Mais bugs são encontrados nas fases de teste "mais baratas", as equipes adicionam testes automatizados para os bugs encontrados durante testes exploratórios e em produção, além de adicionar testes de unidade para detectar bugs descobertos em testes de aceitação.
Tempo gasto corrigindo falhas em testes de aceitação. Alteração no tempo gasto na correção de falhas de testes ao longo do tempo. (Deve reduzir.) Os desenvolvedores podem facilmente corrigir falhas nos testes de aceitação.
Testes automatizados são significativos. Acompanhe a quantidade de falhas de testes automatizados que representam um defeito real e a quantidade que foi mal codificada. As falhas nos testes sempre indicam um defeito real no produto.
Testes automatizados são executados no pipeline de entrega. Verifique (sim/não) se todos os conjuntos de testes são executados em cada gatilho do pipeline. Testes automatizados são executados como parte do pipeline principal e do fluxo de trabalho.

A seguir