Estou trabalhando no desenvolvimento de um projeto antigo escrito em Java. Temos mais de 10 milhões de LOC e, pior ainda, mais de 4000 testes funcionais.
Os testes, programados por Hudson, estão falhando loucamente a cada mudança maior de código. A verificação da falha do teste - se houver um problema no produto ou no teste, leva meses. Não podemos remover os testes antigos porque não sabemos o que eles estão testando!
O que podemos fazer? Como proceder com essa quantidade de testes herdados?
integration-tests
legacy-code
jenkins
Hector Brosuli
fonte
fonte
Respostas:
Abandone-os.
Sei que é difícil deixar de lado algo que foi claramente muito esforço para produzir, mas os testes não estão funcionando para você, estão trabalhando contra você. Um conjunto de testes deve dar a você confiança de que o sistema faz o que deve fazer. Se não fizer isso, é um passivo em vez de um ativo. Não importa se o sistema ou os testes estão com defeito - desde que a execução do conjunto de testes sinalize grandes quantidades de erros, ele não pode cumprir seu objetivo.
O que você precisa agora é de um novo conjunto de testes que é executado sem erros. Isso significa que inicialmente terá pouca cobertura, na verdade quase nenhuma cobertura. Sempre que você conserta ou dedica um tempo para entender completamente algo sobre seu sistema, você reordena esse conhecimento em um teste. Com o tempo, isso produzirá uma nova rede de segurança na qual você poderá construir no futuro. Tentar consertar uma rede de segurança antiga e mal compreendida é um tempo que quase nunca vale a pena.
Eu até defendia a transferência de testes do antigo pacote para o novo. Claro, alguns deles podem ter sucesso agora, mas é porque estão testando exatamente o que deveriam ou apenas porque alguns tiros aleatórios sempre atingem o alvo? Obviamente, você precisa ser pragmático sobre o que pode e o que não pode ser feito com o esforço disponível, mas não pode se comprometer com o princípio de que um conjunto de testes deve ser executado de maneira limpa para realizar seu trabalho .
fonte
Vá e corrija os testes.
Seu maior erro é que você permitiu que os testes falhassem e obviamente ignorou por um tempo. O que você tem não são "testes herdados" - você está trabalhando em um código herdado. E considero todo código escrito sem testes como legado.
Parece que há um problema ainda maior em sua organização, pois você não está trabalhando com requisitos claros. Não consigo entender que você (ou outra pessoa) não pode confirmar o comportamento correto.
fonte
Os testes são valiosos. No mínimo, eles registram que alguém considerou que deveria gastar tempo escrevendo-os; portanto, presumivelmente, eles tiveram algum valor para alguém uma vez. Com sorte, eles conterão um registro completo de todos os recursos e bugs em que a equipe já trabalhou - embora também possam ter sido uma maneira de atingir um número arbitrário de cobertura de teste sem ser cuidadosamente pensado. Até você olhar para eles, você não saberá qual é o caso aqui.
Se a maioria dos seus testes passar na maior parte do tempo, apenas dê uma olhada e invista o tempo em descobrir o que os poucos testes que falharam estavam tentando fazer e corrigi-los ou melhorá-los para que o trabalho seja mais fácil na próxima vez. Nesse caso, pule para a seção Determinar a intenção de cada teste , para obter alguns conselhos sobre o que fazer com um pequeno número de testes com falha.
Por outro lado, você pode se deparar com uma compilação vermelha agora, e centenas ou até milhares de testes que não passaram por um tempo, e Jenkins não é verde há muito tempo. Nesse momento, o status de criação do Jenkins se tornou inútil e um indicador importante dos problemas com seu check-in não está mais funcionando. Você precisa corrigir isso, mas não pode parar todo o progresso enquanto arruma a bagunça na sua sala de estar.
Para manter sua sanidade mental enquanto executa a arqueologia necessária para determinar qual valor pode ser recuperado dos testes que falharam, recomendo as seguintes etapas:
Desative temporariamente os testes com falha.
Existem várias maneiras de fazer isso, dependendo do seu ambiente, que você não descreve claramente, por isso não posso recomendar nenhuma.
Algumas estruturas suportam a noção de falhas esperadas. Se o seu for o caso, isso é ótimo, pois você verá uma contagem regressiva de quantos testes restam nesta categoria e será informado se alguns deles começarem a passar inesperadamente.
Algumas estruturas oferecem suporte a grupos de testes e permitem que você informe ao Hudson apenas para executar alguns dos testes ou ignorar um grupo de testes. Isso significa que você pode ocasionalmente executar o grupo de teste manualmente para ver se algum deles está passando.
Algumas estruturas permitem que você anote ou marque testes únicos para serem ignorados. É mais difícil administrá-los como um grupo nesse caso, mas impede que eles o distraiam.
Você pode mover os testes para uma árvore de origem que normalmente não está incluída na compilação.
In extremis, você pode excluir o código do HEAD do sistema de controle de versão, mas isso tornará mais difícil reconhecer quando a terceira fase for concluída.
O objetivo é fazer com que Jenkins fique verde o mais rápido possível, para que você possa começar a se mover na direção certa o mais rápido possível.
Mantenha os testes relevantes.
Resolva para adicionar novos testes ao adicionar ou modificar o código e comprometa-se a manter todos os testes aprovados.
Os testes podem falhar por vários motivos, incluindo o fato de que não eram testes bem escritos para começar. Mas uma vez que você tenha Jenkins verde, mantê-lo assim é realmente importante.
Acostume-se a escrever bons testes e faça disso um grande negócio se os testes começarem a falhar.
Determine a intenção de cada teste.
Passe pelos testes desativados, um por um. Comece com os que afetam os módulos que você altera com mais frequência. Determine a intenção do teste e o motivo da falha.
Ele testa um recurso que foi removido da base de código de propósito? Então você provavelmente pode excluí-lo.
Está pegando um bug que ninguém notou ainda? Restabeleça o teste e corrija o erro.
Está falhando porque estava fazendo suposições injustificadas (por exemplo, assumindo que o texto do botão sempre estaria em inglês, mas agora você localizou seu aplicativo para vários idiomas)? Depois, descubra como fazer o teste se concentrar em uma única coisa e isolá-lo das alterações não relacionadas da melhor maneira possível.
O teste se estende por todo o aplicativo e representa um teste do sistema? Em seguida, remova-o do seu conjunto principal de testes Jenkins e adicione-o ao conjunto Regression que é executado com menos frequência.
A arquitetura do aplicativo mudou além do reconhecimento, para que o teste não faça mais nada útil? Delete isso.
O teste foi adicionado para aumentar artificialmente as estatísticas de cobertura do código, mas na verdade nada mais é do que confirmar que o código é compilado corretamente e não entra em um loop infinito? Ou então, o teste simplesmente confirma que a estrutura de simulação selecionada retorna os resultados que você acabou de informar? Delete isso.
Como resultado disso, alguns testes permanecerão, alguns serão modificados, outros serão divididos em vários pedaços independentes e pequenos, e alguns serão removidos. Enquanto você ainda estiver progredindo com novos requisitos, reservar um pouco de tempo para lidar com dívidas técnicas como essa é a responsabilidade.
fonte
4000 testes são um problema intratável. 40 testes são mais tratáveis. Selecione aleatoriamente um número gerenciável de testes para executar e analisar. Classifique os resultados como:
Se muitos testes se enquadram na primeira categoria, talvez seja hora de lançar seu conjunto de testes atual e reunir um útil para o código atual.
Se muitos dos testes estão falhando de uma maneira que informa sobre um problema no seu código, você precisa trabalhar com os testes com falha corrigindo as coisas. Você pode achar que a correção de um ou dois erros gera um grande número de testes.
fonte
Se esta afirmação for verdadeira,
isso implica que, se você reverter para o código imediatamente antes de uma "alteração maior do código", muitos dos testes serão aprovados novamente. Depois de fazer isso, pegue um pedaço menor de alterações e veja quais testes estão falhando recentemente. Isso o ajudará a isolar melhor quais alterações de código estão causando a falha de quais testes. Para cada teste, depois de isolar o problema, você poderá determinar se o novo código foi defeituoso ou se o teste foi. Se houver algum problema com o novo código, compare-o com a versão mais recente, caso esse bug específico já tenha sido corrigido.
Repita até que você tenha a base de código mais recente.
Isso pode parecer uma tarefa esmagadora, mas é muito provável que quando você seguir esse caminho e começar a isolar alguns dos problemas, um padrão começará a surgir, o que pode acelerar bastante o processo. Por exemplo:
fonte
Se você não souber o que eles estão testando, remova-os até saber. Testes são coisas fluidas; se você remover um recurso que não é mais necessário, deverá esperar alterar o teste que testa esse recurso! Portanto, a menos que você saiba o que os testes estão testando, não terá esperança de alterar a base de código com eles.
Você pode configurar o sistema de teste nas máquinas dos desenvolvedores e executá-lo para que os desenvolvedores possam ver com quais partes os testes estão interagindo, espero fornecer essa documentação ausente e familiarizar-se com a base de código que você não está mudando corretamente ou não mais testes corretamente.
Em resumo - se seus testes antigos falharem quando você faz alterações, as alterações no código não são boas. Use esses testes como um meio de educação sobre como o sistema funciona.
fonte
@Ignore
anotação do JUnit - você pode manter seus testes, mas não executá-los. Então é simplesmente uma questão de reativá-los e corrigi-los um de cada vez. Ele permite que você restrinja seu foco a apenas alguns testes de cada vez, em vez de ficar sobrecarregado com milhares de falhas.A coisa mais importante que eu faria é voltar aos fundamentos do que os testes devem fazer e o que a empresa precisa para continuar em movimento. O trabalho do teste é identificar problemas antes que eles se tornem caros para corrigir posteriormente. Eu acho que a palavra-chave nessa frase é "cara". Esses problemas precisam de uma solução comercial. Problemas caros estão aparecendo em campo? Nesse caso, o teste está falhando completamente.
Sua gerência e você precisam chegar a uma verificação da realidade. Você está percebendo que os custos de desenvolvimento estão subindo rapidamente devido a um conjunto de testes herdados. Como esses custos se comparam aos custos de entrega de um produto com defeito porque você desativou os testes? Como eles se comparam à tarefa onerosa de realmente descobrir quais comportamentos os usuários precisam (quais são as coisas que devem ser testadas)?
Esses são problemas que precisam de soluções de negócios porque afetam o lado comercial do trabalho. Você está entregando produtos a um cliente, e esse é um limite pelo qual os negócios estão muito interessados. Eles podem ser capazes de identificar soluções que você, como desenvolvedor, não pode. Por exemplo, pode ser razoável que eles forneçam dois produtos: um produto "legado" para aqueles que precisam de confiabilidade e estão dispostos a renunciar a novos recursos, com um produto "visionário" que pode ter mais falhas, mas é pioneiro. Isso daria a você a oportunidade de desenvolver dois conjuntos independentes de testes ... um herdado com 4000 e outro com mais testes que você acha que precisam ser feitos (e documentá-los para que esse processo não se repita).
Então, a arte começa: como você pode gerenciar esse animal de duas cabeças para que os avanços em um ramo também ajudem o outro ramo? Como as atualizações da ramificação "visonary" podem voltar para a ramificação "legada", apesar dos rígidos requisitos de teste. Como as solicitações contínuas de clientes na filial "herdada" moldam melhor sua compreensão dos requisitos que seus clientes herdados precisariam se você re-mesclasse os produtos?
fonte
É exatamente por isso que você deve remover os testes antigos! Se você não sabe o que eles estão fazendo, o fracasso não faz sentido e executá-los é uma perda de tempo. Jogue-os fora e comece de novo.
fonte