Escrevendo testes para código existente

67
Suponha que alguém tenha um programa relativamente grande (digamos, 900k SLOC em C #), todos comentados / documentados completamente, bem organizados e funcionando bem. Todo o código base foi escrito por um único desenvolvedor sênior que não está mais na empresa. Todo o código é testável como está e o IoC é usado em todo o processo - exceto por alguma estranha razão pela qual eles não escreveram nenhum teste de unidade. Agora, sua empresa quer ramificar o código e deseja que testes de unidade sejam adicionados para detectar quando as alterações quebrarem a funcionalidade principal.

  • A adição de testes é uma boa ideia?
  • Se sim, como alguém poderia começar algo assim?

EDITAR

OK, então eu não esperava respostas que fizessem bons argumentos para conclusões opostas. A questão pode estar fora das minhas mãos de qualquer maneira. Eu também li as "perguntas duplicadas" e o consenso geral é que "escrever testes é bom" ... sim, mas não muito útil neste caso em particular.

Eu não acho que estou sozinho aqui pensando em escrever testes para um sistema legado. Eu vou manter métricas sobre quanto tempo é gasto e quantas vezes os novos testes detectam problemas (e quantas vezes eles não). Eu voltarei e atualizarei isto daqui a um ano ou mais com meus resultados.

CONCLUSÃO

Então, basicamente, é impossível simplesmente adicionar o teste unitário ao código existente com qualquer aparência de ortodoxia. Uma vez que o código esteja funcionando, você obviamente não pode fazer luz vermelha / verde em seus testes, mas normalmente não sabe quais comportamentos são importantes para testar, não sabe por onde começar e certamente não fica claro quando você termina. Realmente, até mesmo fazer esta pergunta perde o ponto principal de escrever testes em primeiro lugar. Na maioria dos casos, achei mais fácil reescrever o código usando TDD do que decifrar as funções pretendidas e adicionar retroativamente testes unitários. Ao consertar um problema ou adicionar um novo recurso é uma história diferente, e acredito que este é o momento de adicionar testes unitários (como alguns apontam abaixo). Eventualmente, a maioria dos códigos é reescrita, muitas vezes mais cedo do que você esperaria - tendo essa abordagem, consegui adicionar cobertura de teste a um pedaço surpreendentemente grande da base de código existente.

    
por Paul 06.08.2013 / 17:27
fonte

7 respostas

68

Embora os testes sejam uma boa ideia, a intenção era que o codificador original os construísse enquanto criava o aplicativo para capturar seu conhecimento de como o código deve funcionar e o que pode quebrar, que teria sido transferido para você.

Ao adotar essa abordagem, há uma alta probabilidade de você escrever os testes com menor probabilidade de quebrar e perder a maioria dos casos de borda que teriam sido descobertos durante a criação do aplicativo.

O problema é que a maior parte do valor virá das 'armadilhas' e de situações menos óbvias. Sem esses testes, o conjunto de testes perde virtualmente toda a sua eficácia. Além disso, a empresa terá uma falsa sensação de segurança em torno de seu aplicativo, já que não será significativamente mais prova de regressão.

Normalmente, a maneira de lidar com esse tipo de codebase é escrever testes para novos códigos e refatorar códigos antigos até que a base de código legada seja totalmente refatorada.

Além disso, veja .

    
por 06.08.2013 / 18:02
fonte
36

Sim, adicionar testes é definitivamente uma boa ideia.

Você diz que está bem documentado e isso coloca você em uma boa posição. Tente criar testes usando essa documentação como um guia, concentrando-se em partes do sistema que são críticas ou sujeitas a alterações frequentes.

Inicialmente, o tamanho da base de código provavelmente parecerá avassalador em comparação com a pequena quantidade de testes, mas não há uma abordagem big bang, e fazer um começo em algum lugar é mais importante do que agonizar sobre o que a melhor abordagem será.

Eu recomendaria o livro de Michael Feathers, Trabalhando efetivamente com o código herdado , para um bom conselho detalhado.

    
por 06.08.2013 / 17:58
fonte
21

Nem todos os testes de unidade têm o mesmo benefício. O benefício de um teste de unidade vem quando ele falha. Quanto menos provável é falhar, menos benéfico é. É mais provável que o código novo ou alterado recentemente contenha bugs do que o código raramente alterado que é bem testado na produção. Portanto, os testes unitários em código novo ou alterado recentemente têm maior probabilidade de serem mais benéficos.

Nem todos os testes unitários têm custo igual. É muito mais fácil testar o código trivial que você criou hoje em dia do que o código complexo criado por alguém há muito tempo. Além disso, o teste durante o desenvolvimento geralmente economiza tempo de desenvolvimento. No código legado, as economias de custo não estão mais disponíveis.

Em um mundo ideal, você teria todo o tempo necessário para testar o código legado de teste, mas no mundo real, em algum momento, os custos da adição de testes unitários ao código legado superam os benefícios . O truque é identificar esse ponto. Seu controle de versão pode ajudar, mostrando-lhe o código mais recentemente alterado e alterado com mais freqüência, e você pode começar colocando-os em teste de unidade. Além disso, quando você fizer alterações no futuro, coloque essas alterações e o código relacionado no teste de unidade.

Seguindo esse método, você terá uma boa cobertura nas áreas mais benéficas. Se, em vez disso, você passar meses fazendo testes de unidade antes de retomar atividades de geração de receita, isso pode ser uma decisão desejável de manutenção de software, mas é uma péssima decisão comercial.

    
por 06.08.2013 / 20:03
fonte
8

Is adding tests a good idea?

Absolutamente, embora eu ache um pouco difícil acreditar que o código esteja limpo e funcionando bem e usando técnicas modernas e simplesmente não tenha testes unitários. Tem certeza de que eles não estão sentados em uma solução separada?

De qualquer forma, se você for estender / manter o código, os testes unitários verdadeiros são inestimáveis para esse processo.

If so, how would one even start on something like this?

Um passo de cada vez. Se você não estiver familiarizado com o teste de unidade, aprenda um pouco. Uma vez que você esteja confortável com os conceitos, escolha uma pequena seção do código e escreva testes para ela. Então o próximo e o próximo. A cobertura de código pode ajudá-lo a encontrar pontos que você perdeu.

Provavelmente, é melhor escolher coisas perigosas / arriscadas / vitais para testar primeiro, mas você pode ser mais eficiente testando algo direto para entrar em um primeiro estágio - especialmente se você / a equipe não estiver acostumado com a base de código e / ou teste de unidade.

    
por 06.08.2013 / 17:34
fonte
3

Sim, ter testes é uma boa ideia. Eles ajudarão a documentar as bases de código existentes, conforme o esperado, e detectar qualquer comportamento inesperado. Mesmo se os testes falharem inicialmente, deixe-os e depois refatore o código mais tarde, para que eles passem e se comportem como pretendido.

Comece a escrever testes para classes menores (aquelas que não têm dependências e são relativamente simples) e passe para classes maiores (aquelas que têm dependências e são mais complexas). Vai levar um bom tempo, mas seja paciente e persistente para que você possa cobrir a base de código o máximo possível.

    
por 06.08.2013 / 17:33
fonte
3

OK, vou dar a opinião contrária ...

Adicionar testes a um sistema existente e em funcionamento irá alterar esse sistema, a menos que seja, o sistema está todo escrito com a zombaria em mente desde o início. Eu duvido, embora seja bem possível que haja uma boa separação de todos os componentes com limites facilmente definidos nos quais você pode deslizar suas interfaces simuladas. Mas se não for, então você terá que fazer mudanças significativas (relativamente falando) que podem quebrar as coisas. Na melhor das hipóteses, você gastará muito tempo escrevendo esses testes, tempo que poderia ser melhor gasto escrevendo uma carga de documentos detalhados de projeto, documentos de análise de impacto ou documentos de configuração de solução. Afinal de contas, esse é o trabalho que seu chefe quer mais que testes de unidade. Não é?

De qualquer forma, eu não adicionaria nenhum teste de unidade.

Eu me concentraria em ferramentas de teste externas e automatizadas que lhe darão uma cobertura razoável sem alterar nada. Então, quando você vem para fazer modificações ... é quando você pode começar a adicionar testes de unidade dentro da base de código.

    
por 13.08.2013 / 23:36
fonte
2

Frequentemente eu corri para essa situação, herdei uma grande base de código sem cobertura de teste adequada ou nenhuma, e agora sou responsável por adicionar funcionalidade, corrigir bugs, etc.

Meu conselho é ter certeza e testar o que você adiciona, e se você corrigir bugs ou alterar casos de uso no código atual, o autor testa então. Se você tiver que tocar em algo, escreva testes nesse ponto.

Quando isso acontece, é quando o código existente não está bem estruturado para testes de unidade, portanto, você gasta muito tempo em refatoração para poder adicionar testes para pequenas alterações.

    
por 06.08.2013 / 20:28
fonte