A adição de testes de unidade faz sentido para um código legado conhecido?


21
  • Estou falando de testes de unidade no sentido TDD. ("Integração" não automatizada, ou como você gostaria de chamar de testes.)
  • Código legado como em: código (C ++) sem testes. (veja: Michael Feathers ' trabalhando efetivamente com o código legado )
  • Mas também código legado, como em: código com o qual nossa equipe trabalha nos últimos 10 a 5 anos; portanto, muitas vezes temos uma boa idéia de onde colocar as coisas para mudar alguma coisa.
  • Temos testes de unidade em vigor (via Boost.Test) para alguns módulos que vieram mais tarde ou foram adequados para testes de unidade (contêineres específicos de aplicativos comuns, material de cadeia, auxiliares de rede etc.)
  • Ainda não temos testes de aceitação automatizados adequados.

Agora, recentemente, tive o "prazer" de implementar três novos recursos voltados para o usuário.

Cada um deles levou cerca de 1-2 horas para me familiarizar com as partes do código que eu precisava alterar, 1-2 horas para implementar o (pequeno) código que eu precisava mudar e mais 1-2 horas para garantir que o aplicativo correu corretamente depois e fez foi o que deveria fazer.

Agora, eu realmente adicionei pouco código. (Acho que um método e algumas linhas de chamada para cada recurso.)

Fatorar esse código (através de qualquer um dos métodos sugeridos no WEwLC ), para que um teste de unidade fizesse sentido (e não fosse uma tautologia completa) levaria facilmente mais 2-4 horas, se não mais. Isso acrescentaria 50% a 100% de tempo a cada recurso, sem benefício imediato, pois

  1. Não precisei do teste de unidade para entender nada sobre o código
  2. O teste manual é a mesma quantidade de trabalho, pois ainda preciso testar se o código está corretamente integrado ao restante do aplicativo.

Concedido, se , mais tarde, "alguém" aparecer e tocar esse código, ele teoricamente poderia se beneficiar desse teste de unidade. (Apenas teoricamente, como a ilha de código testada viveria em um oceano de código não testado.)

Então, "desta vez", optei por não fazer o trabalho duro de adicionar um teste de unidade: as alterações de código para colocar essas coisas em teste teriam sido significativamente mais complexas do que as alterações de código para obter o recurso corretamente (e de forma limpa) implementado.

Isso é algo típico para código legado fortemente acoplado? Sou preguiçoso / estabelecemos prioridades erradas como equipe? Ou sou prudente, apenas testando coisas onde a sobrecarga não é muito alta?


e se algum outro departamento assumir o seu "código legado conhecido"? O que os caras farão com isso?
Alex Theodoridis

Respostas:


18

Você tem que ser pragmático sobre essas situações. Tudo precisa ter um valor comercial, mas a empresa precisa confiar em você para julgar qual é o valor do trabalho técnico. Sim, sempre há um benefício em realizar testes de unidade, mas esse benefício é grande o suficiente para justificar o tempo gasto?

Eu argumentaria sempre sobre o novo código, mas, no código legado, você deve fazer uma chamada de julgamento.

Você está nessa área de código frequentemente? Depois, há um argumento para a melhoria contínua. Você está fazendo uma mudança significativa? Depois, há um caso em que já é um novo código. Mas se você estiver criando um código de uma linha em uma área complexa que provavelmente não será tocada novamente por um ano, é claro que o custo (sem mencionar o risco) da reengenharia é muito alto. Basta colocar uma linha de código e ir tomar um banho rápido.

Regra prática: sempre pense: " Acredito que os negócios se beneficiam mais desse trabalho técnico que acho que devo fazer do que o trabalho que eles pediram e que será adiado como resultado? "


O que é um bom pedaço de código? Um que seja bem projetado, testado, documentado e à prova do futuro ou pelo qual você seja pago? Como sempre: você pode tê-lo bem ; você pode comprar barato ; você pode ter rápido . Escolha dois, o terceiro é o seu custo.
Sardathrion - Restabelece Monica

2
"Eu argumentaria sempre sobre o novo código" ... "novo código" em uma base de código herdada ou "novo novo código"? :-)
Martin Ba

pdr tem a ideia certa. É uma decisão de engenharia (uma com trocas). Geralmente, se você tem um grande pedaço de código verificado, é uma boa ideia deixá-lo em paz. Eu vi um esforço do TDD no código legado (apenas um ano, mas isso é o suficiente) que acabou custando meses e acabou gastando dinheiro e quebrando um aplicativo legado por meses até que os erros introduzidos pelo refator do TDD fossem corrigidos. Se o código / recurso estiver pronto e testado, não o interrompa para adicionar instrumentação (TDD) para lhe dizer algo que você já sabia de qualquer maneira (que funciona).
anon

10

O ganho de testes de unidade no sentido de TDD é obter algo que se sustenta por si só, sem a necessidade de tradição oral construída ao longo dos anos por uma equipe estável.

É uma grande sorte que a mesma equipe esteja no mesmo projeto há tanto tempo. Mas isso acabará mudando. As pessoas ficam doentes, entediadas ou promovidas. Eles se movem, se aposentam ou morrem. As novas vêm com novas idéias e o desejo de refatorar tudo do jeito que aprenderam na escola. As empresas são vendidas e compradas. As políticas de gerenciamento mudam.

Se você deseja que seu projeto sobreviva, você deve prepará-lo para as mudanças.


3

Escrever testes de unidade é uma prova futura do seu código. Se a base de código não tiver testes, você deverá adicionar novos testes para todos os novos recursos, pois torna essa parte do código um pouco mais robusta.

Acho que adicionar testes, mesmo no código legado, é benéfico a médio e longo prazo. Se sua empresa não se importa com o médio e o longo prazo, eu procuraria outra empresa. Além disso, não acho que demore mais tempo para testar manualmente do que para escrever um teste de unidade definido. Se isso acontecer, você precisará praticar o kata de código focado em escrever testes.


1
Mas, mas, mas! :-) Esse pouco deve se traduzir em um aumento de 100% no tempo necessário para implementar um novo recurso. Ele não diminuir o tempo necessário para implementar recursos subsequentes. Ele pode diminuir o tempo necessário ao mudar coisas.
Martin Ba

3
Você está certificando-se de que as alterações nessa área do código não introduzam novos bugs, que novos (usuários menos experientes) possam entender claramente o código e que os efeitos colaterais que afetam essa área são tosse no momento do teste e não no lançamento Tempo. O teste ajuda a verificar se o código faz o que deveria, não facilita a adição de recursos posteriormente. Acho que adicionar testes, mesmo no código legado, é benéfico a médio e longo prazo . Se sua empresa não se importa com o médio e o longo prazo, eu procuraria outra empresa.
Sardathrion - Restabelece Monica

1
@ Martin, porque claramente o que você faz é codificar o que você acha que o recurso deveria ser e depois enviá-lo. Nenhum teste é realizado em nenhum momento ... não, espere. Como desenvolvedores, todos testamos nosso código (pelo menos manualmente) antes de dizer que está pronto. Substituir "manualmente" por "escrevendo um teste automatizado" não representa um aumento de 100% no tempo. Freqüentemente, acho que é quase o mesmo tempo.
quer

1
@Kaz - "Substituir" manualmente "por" escrevendo um teste automatizado "não é um aumento de 100% no tempo. Freqüentemente, acho que é quase o mesmo tempo." - YMMV, mas para a minha base de código, isso está claramente errado (conforme descrito na pergunta).
Martin Ba

3
@ Kaz: O que eu :-) quis dizer foi: Um teste de unidade testa meu código isoladamente. Se eu não escrever um teste de unidade, não testarei o código isoladamente, mas apenas se o código for chamado corretamente e produzir o resultado desejado no aplicativo. Esses dois pontos (chamados corretamente e o aplicativo faz o que deveria) devem ser testados de qualquer maneira (manualmente) e não são cobertos por um teste de unidade. E o teste de unidade não abordaria esses dois pontos, mas "apenas" testaria minha função isoladamente. (E esse teste de unidade-teste seria adicional e não seria compensado por nada, tanto quanto eu possa ver.) #
Martin Ba

2

Certamente, as práticas recomendadas exigem que você teste de unidade qualquer código que você alterar. A codificação do mundo real, no entanto, envolve muitos compromissos, tempo e materiais são finitos.

O que você precisa fazer é avaliar o custo em termos reais de correção de bugs e modificações sem testes de unidade. Você pode avaliar o investimento na criação desses testes. Os testes de unidade reduzem muito o custo de trabalhos futuros, mas têm um preço agora.

Resumindo, se o seu sistema raramente é alterado, pode não valer a pena escrever testes de unidade, mas se estiver sujeito a alterações regulares, valerá a pena.


1

Todas essas pequenas decisões racionais para não criar testes estão criando uma dívida técnica incapacitante que voltará para assombrá-lo quando alguém sair e um novo contratado tiver que entrar e se atualizar.

Sim, pode custar mais 2-3 horas para escrever os testes de unidade, mas se o código for enviado de volta dos testes, você terá que testar tudo manualmente novamente e documentar seus testes novamente - você faz isso, não é? Caso contrário, como alguém sabe o que você testou e quais valores usou?

Os testes de unidade documentam o comportamento esperado do código, os dados de teste usados ​​para verificar a funcionalidade e dão aos novos codificadores confiança razoável de que eles não quebraram algo ao fazer alterações.

Hoje, leva algumas horas mais do que testes manuais, mas você está testando toda vez que faz alguma alteração, economizando horas ao longo da vida útil do código.

No entanto, se você souber que o código será retirado em alguns anos, tudo o que eu disse mudou porque você não terminará de colocar testes no código e isso nunca será recompensado.


"e documente seus testes novamente - você faz isso, não é?" - {colocando chapéu cínico:} Claro que não. Não estamos na terra das fadas dos desenvolvedores. O material é implementado, testado e enviado. Mais tarde, fica quebrado, consertado, testado e enviado.
Martin Ba

Espero que tudo seja testado manualmente, independentemente do número de testes de unidade. Testes de aceitação automatizados são outra questão completamente. Porém, os testes de aceitação não são mais difíceis pelo legado da base de código, portanto estão fora do escopo aqui.
quer

2
mcottle - Está faltando um ponto vital . O teste de unidade não diminuirá o tempo necessário para realizar o "teste manual de funcionalidade" do recurso finalizado. Eu ainda tenho que clique com o botão através de todos os diálogos envolvidos com um subconjunto prudente de entradas possíveis para garantir que o aplicativo acabado real como construiu faz o que é suposto fazer. (Admito que, teoricamente , o teste de unidade pode ajudar a limitar esse ciclo de teste manual a apenas um loop, se os testes de unidade garantirem que não encontrarei nenhum problema óbvio apenas durante o teste manual.)
Martin Ba

0

O valor dos testes de unidade não reside apenas no teste de um novo recurso quando ele é desenvolvido. O benefício dos testes de unidade é obtido principalmente no futuro.

Sim, pode ser necessário gastar o que parece ser uma quantidade excessiva de tempo para tornar seu código legado testável.

Mas, se não o fizer, você passará, ou certamente deve , gastar muitas, muitas e muito mais horas testando o recurso. Não apenas no seu desenvolvimento inicial, mas com todas as novas versões do seu software. Sem os testes de unidade, você e outras formas de teste automatizado não têm outra opção a não ser passar muitas horas de teste manual para garantir que seu recurso não foi quebrado inadvertidamente, mesmo quando esse recurso em si não foi alterado.


1
"Sem testes de unidade, você não tem outros meios para garantir que seu recurso não seja quebrado inadvertidamente, mesmo quando esse recurso em si não foi alterado." - Testes unitários não ajudarão. Para ter certeza , eu teria que ter testes de integração / aceitação automatizados.
Martin Ba

Sim, testes de unidade são apenas o primeiro passo. Resposta editada para esclarecer
Marjan Venema
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.