É uma boa idéia escrever todos os casos de teste possíveis após transformar a equipe em TDD para obter uma cobertura completa?


17

Suponha que tenhamos um grande aplicativo de nível corporativo sem nenhum teste de unidade / funcional. Não houve processo de desenvolvimento orientado a testes durante o desenvolvimento devido a prazos muito apertados (sei que nunca devemos prometer prazos apertados quando não tivermos certeza, mas o que está feito está feito!)

Agora que todos os prazos passaram e tudo está calmo, todos concordaram em nos transformar em uma equipe produtiva baseada em TDD / BDD ... Yay!

Agora, a pergunta é sobre o código que já temos: (1) Ainda é bom ou uma boa ideia parar a maior parte do desenvolvimento e começar a escrever casos de teste possíveis desde o início, mesmo que tudo esteja funcionando completamente OKAY (ainda!) ? Ou (2) é melhor esperar que algo ruim aconteça e, durante a correção, escreva novos testes de unidade ou (3) até esqueça os códigos anteriores e apenas escreva testes de unidade apenas para os novos códigos e adie tudo para o próximo refator principal.

Existem alguns artigos bons e relacionados, como este . Ainda não tenho certeza se vale a pena investir nisso, considerando que temos um tempo muito limitado e muitos outros projetos / obras estão esperando por nós.

Nota : Esta pergunta está explicando / imaginando uma situação totalmente embaraçosa em uma equipe de desenvolvimento. Isso não é sobre mim ou sobre qualquer um dos meus colegas; é apenas uma situação imaginária. Você pode pensar que isso nunca deve acontecer ou o gerente de desenvolvimento é responsável por essa bagunça! Mas de qualquer maneira, o que está feito está feito. Se possível, não faça voto negativo apenas porque acha que isso nunca deveria acontecer.



6
Você provavelmente deve estar se preparando para a próxima vez que os prazos chegarem e não poderá mais usar o TDD. Possivelmente, dizendo a quem dirigiu a última rodada de endividamento técnico por que essa não foi uma ótima idéia.
jonrsharpe

1
@gnat Eu acho que não é uma pergunta duplicada. O mencionado equipa não tem qualquer tipo de testes (nem mesmo os testes de integração)
Michel Gokan

1
@gnat a pergunta é: o que acontecerá com nossos novos testes de unidade? Eles podem parecer incompletos ou até inúteis sem escrever todos os testes de unidade dos códigos escritos anteriormente. A pergunta que você menciona não cobre essa preocupação específica.
Michel Gokan

1
Não é possível escrever todos os casos de teste possíveis. Só é útil escrever todos os casos de teste de seu interesse. Por exemplo, se você precisar de uma função que aceite um intvalor e retorne algo específico, não é possível escrever um teste de unidade para todos os intvalores possíveis , mas provavelmente faz sentido testar alguns valores úteis que podem desarmar o código, como números negativos (incluindo minint), zero maxint, etc. para garantir que alguns casos extremos sejam cobertos.
Christopher Schultz

Respostas:


36

Não houve processo de desenvolvimento orientado a testes durante o desenvolvimento devido a prazos muito apertados

Esta afirmação é muito preocupante. Não porque significa que você desenvolveu sem TDD ou porque não está testando tudo. Isso é preocupante, porque mostra que você acha que o TDD o atrasará e fará com que você perca um prazo.

Contanto que você veja dessa maneira, você não está pronto para TDD. O TDD não é algo em que você possa se adaptar gradualmente. Você sabe como fazê-lo ou não. Se você tentar fazer isso no meio do caminho, você fará com que você fique mal.

TDD é algo que você deve praticar primeiro em casa. Aprenda a fazê-lo, porque ajuda a codificar agora . Não porque alguém lhe disse para fazê-lo. Não porque ajudará quando você fizer alterações mais tarde. Quando se torna algo que você faz porque está com pressa, está pronto para fazê-lo profissionalmente.

TDD é algo que você pode fazer em qualquer loja. Você nem precisa entregar seu código de teste. Você pode guardar para si mesmo se os outros desdenharem os testes. Quando você faz o que é certo, os testes aceleram seu desenvolvimento, mesmo que ninguém mais os execute.

Por outro lado, se outras pessoas amam e executam seus testes, você ainda deve ter em mente que, mesmo em uma loja de TDD, não é seu trabalho verificar os testes. É para criar um código de produção comprovado. Se acontecer de ser testável, puro.

Se você acha que a gerência precisa acreditar no TDD ou que seus colegas codificadores precisam oferecer suporte aos seus testes, então você está ignorando a melhor coisa que o TDD faz por você. Ele mostra rapidamente a diferença entre o que você acha que seu código faz e o que realmente faz.

Se você não consegue ver como isso, por si só, pode ajudá-lo a cumprir um prazo mais rapidamente, então você não está pronto para o TDD no trabalho. Você precisa praticar em casa.

Dito isso, é bom quando a equipe pode usar seus testes para ajudá-los a ler seu código de produção e quando o gerenciamento compra novas ferramentas TDD.

É uma boa ideia escrever todos os casos de teste possíveis após transformar a equipe em TDD?

Independentemente do que a equipe esteja fazendo, nem sempre é uma boa idéia escrever todos os casos de teste possíveis. Escreva os casos de teste mais úteis. 100% de cobertura de código tem um custo. Não ignore a lei dos retornos decrescentes apenas porque é difícil fazer um julgamento.

Economize sua energia de teste para a interessante lógica de negócios. O material que toma decisões e aplica políticas. Teste os pedaços fora disso. O código de cola estrutural óbvio e fácil de ler, chato, que apenas liga as coisas, não precisa de testes tão ruins.

(1) Ainda é bom ou uma boa ideia interromper a maior parte do desenvolvimento e começar a escrever casos de teste possíveis desde o início, mesmo que tudo esteja funcionando completamente OKAY (ainda!)? Ou

Não. Esse é o pensamento "vamos reescrever completamente". Isso destrói o difícil conhecimento adquirido. Não peça tempo para a gerência escrever testes. Basta escrever testes. Depois de saber o que está fazendo, os testes não o atrasarão.

(2) é melhor esperar que algo ruim aconteça e, durante a correção, escreva novos testes de unidade ou

(3) até esqueça os códigos anteriores e apenas escreva testes de unidade apenas para os novos códigos e adie tudo para o próximo grande refatorador.

Vou responder 2 e 3 da mesma maneira. Quando você altera o código, por qualquer motivo, é muito bom se você pode fazer um teste. Se o código é legado, atualmente não é bem-vindo a um teste. O que significa que é difícil testá-lo antes de alterá-lo. Bem, já que você está alterando de qualquer maneira, pode transformá-lo em algo testável e testá-lo.

Essa é a opção nuclear. É arriscado. Você está fazendo alterações sem testes. Existem alguns truques criativos para colocar o código herdado em teste antes de alterá-lo. Você procura as chamadas costuras que permitem alterar o comportamento do seu código sem alterá-lo. Você altera os arquivos de configuração, constrói os arquivos, o que for preciso.

Michael Feathers nos deu um livro sobre isso: Trabalhando efetivamente com o Legacy Code . Leia e você verá que não precisa queimar tudo o que é antigo para criar algo novo.


37
"Os testes aceleram seu desenvolvimento, mesmo que ninguém mais os execute." - Acho que isso é patentemente falso. Este não é o lugar ideal para iniciar uma discussão sobre isso, mas os leitores devem ter em mente que o ponto de vista apresentado aqui não é unânime.
Martin Ba

4
Na verdade, frequentemente os testes aumentam seu desenvolvimento a longo prazo e, para que o TDD seja realmente eficiente, todos precisam acreditar nele; caso contrário, você gastaria metade da sua equipe consertando testes quebrados por outros.
Hspandher

13
"você acha que o TDD o atrasará e fará com que você perca um prazo." Eu acho que provavelmente é esse o caso. Ninguém usa TDD porque espera que seu primeiro prazo seja cumprido mais rapidamente. O benefício real (pelo menos na minha opinião) são os dividendos contínuos que testam o jogo no futuro, para obter regressões e para criar confiança em experiências seguras. Acho que esse benefício supera o custo inicial de escrever testes, a maioria provavelmente concordaria, mas se você tiver que cumprir o prazo apertado que está chegando, não terá realmente uma escolha.
Alexander - Restabelece Monica

1
Acho análogo a comprar uma casa. Se você tivesse o montante fixo para pagar uma casa, economizaria muito em juros e seria ótimo a longo prazo. Mas se você precisa de uma casa imediatamente ... então você é forçado a tomar uma abordagem de curto prazo que é de longo prazo abaixo do ideal
Alexander - Reintegrar Monica

3
TDD = can = aumenta o desempenho se os testes e o código são desenvolvidos em paralelo, enquanto a funcionalidade é nova na mente do desenvolvedor. As revisões de código informarão se outro ser humano acha que o código está correto. Os casos de teste informarão se a especificação, conforme incorporada em um caso de teste, está sendo implementada. Caso contrário, sim, o TDD pode ser uma chatice, especialmente se não houver especificações funcionais e o gravador de teste também estiver fazendo engenharia reversa.
Julie em Austin

22

Ainda é bom ou uma boa idéia interromper a maior parte do desenvolvimento e começar a escrever casos de teste possíveis desde o início?

Dado o código legado 1 , escreva testes de unidade nestas situações:

  • ao corrigir bugs
  • ao refatorar
  • ao adicionar nova funcionalidade ao código existente

Por mais úteis que sejam os testes de unidade, criar um conjunto completo de testes de unidade para uma base de código 1 existente provavelmente não é uma idéia realista. Os poderes que o levaram a cumprir um prazo apertado. Eles não lhe deram tempo para criar testes de unidade adequados enquanto você desenvolvia. Você acha que eles lhe darão tempo suficiente para criar testes para o "programa que funciona"?

1 Código legado é o código sem testes de unidade. Esta é a definição TDD do código legado. Aplica-se mesmo que o código legado seja entregue recentemente [mesmo que a tinta ainda não tenha secado].


Porém, nossos novos testes de unidade para novos recursos podem parecer incompletos ou até inúteis sem a falta de testes de unidade. Não é?
precisa

7
(1) Inútil? Certamente não. No mínimo, eles testam o novo recurso. Da próxima vez que alguém quiser modificar esse recurso, reutilizará grande parte dos testes existentes. (2) incompleto? Talvez talvez não. Se você também criar testes de unidade que testam a funcionalidade herdada da qual o novo recurso depende, os testes poderão ser concluídos o suficiente para fins práticos. Em outras palavras, crie testes de unidade adicionais que penetram na funcionalidade herdada. Penetre a que profundidade? Depende da arquitetura do programa, recursos disponíveis, suporte institucional.
precisa

A desvantagem de "escrever testes quando você precisar deles" é que há um risco aumentado de acabar com uma colcha de retalhos de testes escritos por diferentes desenvolvedores com idéias diferentes. Não estou dizendo que esta resposta esteja errada, mas exige uma mão firme que mantenha a qualidade e o estilo dos testes uniformes.
Flater 26/11

4
A uniformidade do @Flater oferece conforto falso. Quero testes que facilitem a leitura do código de produção. Não são testes que parecem iguais. Perdoarei a mistura de estruturas de teste completamente diferentes se facilitar a compreensão do que o código de produção faz.
candied_orange

2
@ Flater Não afirmei código de produção feio. Afirmo que o objetivo dos testes é tornar o código de produção legível. Aceitarei com prazer uma multidão eclética de testes que facilitam a leitura do código de produção. Tenha cuidado ao tornar a uniformidade uma meta em si mesma. A legibilidade é rei.
candied_orange

12

Na minha experiência, os testes não precisam de cobertura total para serem úteis. Em vez disso, você começa a colher diferentes tipos de benefícios à medida que a cobertura aumenta:

  • mais de 30% de cobertura (também conhecido como alguns testes de integração): se seus testes falharem, algo será extremamente quebrado (ou seus testes serão inadequados). Felizmente, os testes o alertaram rapidamente! Mas os lançamentos ainda exigirão extensos testes manuais.
  • mais de 90% de cobertura (também conhecida como a maioria dos componentes têm testes de unidade superficiais): se os testes forem aprovados, o software provavelmente está bem. As partes não testadas são casos extremos, o que é bom para software não crítico. Mas os lançamentos ainda exigirão alguns testes manuais.
  • cobertura muito alta de funções / instruções / filiais / requisitos: você está vivendo o sonho de TDD / BDD e seus testes são um reflexo preciso da funcionalidade do seu software. Você pode refatorar com alta confiança, incluindo alterações arquiteturais em grande escala. Se os testes passarem, seu software está quase pronto para lançamento; somente alguns testes manuais de fumaça são necessários.

A verdade é que, se você não começar com o BDD, nunca chegará lá, porque o trabalho necessário para testar após a codificação é excessivo. O problema não é escrever os testes, mas conhecer os requisitos reais (em vez de detalhes incidentais da implementação) e ser capaz de projetar o software de uma maneira funcional e fácil de testar. Quando você escreve os testes primeiro ou junto com o código, isso é praticamente gratuito.

Como os novos recursos exigem testes, mas os testes exigem alterações no design, mas a refatoração também exige testes, você tem um problema com galinhas e ovos. À medida que seu software se aproxima de uma cobertura decente, você precisa refatorar cuidadosamente as partes do código em que novos recursos ocorrem, apenas para torná-los testáveis. Isso vai te atrapalhar muito - inicialmente. Porém, refatorando e testando apenas as partes em que é necessário novo desenvolvimento, os testes também se concentram na área em que são mais necessários. O código estável pode continuar sem testes: se fosse de buggy, você teria que alterá-lo de qualquer maneira.

Enquanto você tenta se adaptar ao TDD, uma métrica melhor que a cobertura total do projeto seria a cobertura do teste em partes que estão sendo alteradas. Essa cobertura deve ser muito alta desde o início, embora não seja viável testar todas as partes do código afetadas por uma refatoração. Além disso, você colhe a maioria dos benefícios da alta cobertura de teste nos componentes testados. Isso não é perfeito, mas ainda é bastante bom.

Observe que, embora os testes de unidade pareçam comuns, começar pelas partes menores não é uma estratégia adequada para testar um software legado. Você deseja começar com testes de integração que exercitam grande parte do software de uma só vez.

Por exemplo, eu achei útil extrair casos de teste de integração de arquivos de log do mundo real. É claro que executar esses testes pode levar muito tempo, e é por isso que você pode querer configurar um servidor automatizado que execute os testes regularmente (por exemplo, um servidor Jenkins acionado por confirmações). O custo de configurar e manter um servidor desse tipo é muito pequeno se comparado à não execução de testes regularmente, desde que qualquer falha de teste seja corrigida rapidamente.


"mais de 90% de cobertura (também conhecida como a maioria dos componentes possui testes de unidade superficiais): se seus testes forem aprovados, o software provavelmente ficará bem. As partes não testadas são casos extremos, o que é bom para softwares não críticos ." Isso me parece um pouco estranho, FWIW, eu preferiria ter 30% de cobertura composta principalmente por casos extremos do que 90% de cobertura consistindo inteiramente no comportamento esperado do caminho (o que é fácil para os testadores manuais); Eu recomendo pensar "fora da caixa" ao escrever testes e baseando-os em casos de teste (incomuns) descobertos manualmente sempre que possível.
JRH

5

Não escreva testes para o código existente. Não vale a pena.

O que você fez já é um pouco testado de uma maneira completamente informal - você o testou manualmente constantemente, as pessoas fizeram alguns testes não automáticos, estão sendo usados ​​agora. Isso significa que você não encontrará muitos erros .

O que resta são os bugs em que você não pensou. Mas esses são exatamente os que você não pensou em escrever para os testes de unidade, então provavelmente ainda não os encontrará.

Além disso, uma razão para o TDD é fazer você pensar sobre quais são os requisitos exatos de um pouco de código antes de escrevê-lo. De qualquer maneira diferente, você já fez isso.

Enquanto isso, ainda é tão trabalhoso escrever esses testes quanto teria sido antes. Vai custar muito tempo, para pouco benefício.

E é extremamente chato escrever muitos e muitos testes sem codificação no meio e encontrar quase nenhum erro. Se você começar a fazer isso, as pessoas novas no TDD o odiarão .

Em resumo, os desenvolvedores o odeiam e os gerentes o consideram caro, embora não sejam encontrados muitos bugs. Você nunca chegará à peça TDD real.

Use-o nas coisas que você deseja alterar, como parte normal do processo.


1
Discordo totalmente de "Não escreva testes para o código existente. Não vale a pena". Se o código estiver funcionando razoavelmente adequadamente, os testes poderão ser a única especificação existente. E se o código estiver em manutenção, adicionar testes é a única maneira de garantir que as funções que funcionam não sejam quebradas por alterações aparentemente não relacionadas.
Julie em Austin

3
@JulieinAustin: Por outro lado, sem uma especificação, você não sabe exatamente o que o código deve fazer. E se você ainda não sabe o que o código deve fazer, poderá escrever testes inúteis - ou, pior, enganosos que alteram sutilmente as especificações - e agora é necessário um comportamento acidental e / ou errado.
Chao

2

Um teste é um meio de comunicar entendimento.

Portanto, apenas escreva testes para o que você entende que deve ser verdadeiro.

Você só pode entender o que deve ser verdade quando trabalha com ele.

Portanto, apenas escreva testes para o código com o qual você está trabalhando.

Ao trabalhar com o código, você aprenderá.

Portanto, escreva e reescreva testes para capturar o que aprendeu.

Enxague e repita.

Tenha uma ferramenta de cobertura de código em execução nos seus testes e aceite apenas confirmações na linha principal que não reduzam a cobertura. Eventualmente, você alcançará um alto nível de cobertura.

Se você não trabalha com o código há algum tempo, é necessário tomar uma decisão comercial. Agora é possivelmente tão legado que ninguém em sua equipe sabe como trabalhar com ele. Provavelmente, possui bibliotecas / compiladores / documentação desatualizados, o que é uma enorme responsabilidade em quase todos os aspectos.

Duas opções:

  1. Invista tempo para lê-lo, aprender com ele, escrever testes e refatorá-lo. Pequenos conjuntos de alterações com lançamentos frequentes.
  2. Encontre uma maneira de abandonar esse software. Você não poderia fazer uma modificação quando solicitado de qualquer maneira.

0

(1) Ainda é bom ou uma boa ideia interromper a maior parte do desenvolvimento e começar a escrever casos de teste possíveis desde o início, mesmo que tudo esteja funcionando completamente OKAY (ainda!)?
(2) é melhor esperar que algo ruim aconteça e, durante a correção, escreva novos testes de unidade

Um dos principais objetivos dos testes é garantir que uma alteração não interrompa nada. Este é um processo de três etapas:

  1. Confirme se os testes foram bem-sucedidos
  2. Faça as alterações
  3. Confirme se os testes ainda foram bem-sucedidos

Isso significa que você precisa ter testes de trabalho antes de alterar alguma coisa. Se você escolher o segundo caminho, isso significa que você precisará forçar seus desenvolvedores a escrever testes antes mesmo de tocarem no código. E suspeito fortemente que, quando já enfrentamos uma mudança no mundo real, os desenvolvedores não vão dar aos testes de unidade a atenção que merecem.

Portanto, sugiro dividir as tarefas de gravação e teste para evitar que os desenvolvedores sacrifiquem a qualidade de um pelo outro.

mesmo que tudo esteja funcionando completamente OK (ainda!)?

Apenas para apontar isso especificamente, é um equívoco comum que você só precise de testes quando o código não estiver funcionando. Você precisa de testes quando o código também está funcionando, por exemplo, para provar a alguém que [o bug que ocorre recentemente] não é devido à sua parte, porque os testes ainda estão passando.
Confirmar que tudo ainda funciona como antes era um benefício importante dos testes que você está omitindo quando implica que não precisa de testes quando o código está funcionando.

(3) até esqueça os códigos anteriores e apenas escreva testes de unidade apenas para os novos códigos e adie tudo para o próximo grande refatorador

Idealmente, todo o código-fonte existente deve agora fazer testes de unidade. No entanto, existe um argumento razoável de que o tempo e o esforço (e o custo) necessários para fazer isso simplesmente não são relevantes para determinados projetos.
Por exemplo, aplicativos que não estão mais sendo desenvolvidos e não devem mais ser alterados (por exemplo, o cliente não o usa mais ou o cliente não é mais um cliente), você pode argumentar que não é relevante testar mais esse código .

No entanto, não é tão claro onde você desenha a linha. Isso é algo que uma empresa precisa analisar em uma análise de custo-benefício. Escrever testes custa tempo e esforço, mas eles esperam algum desenvolvimento futuro para esse aplicativo? Os ganhos de ter testes de unidade superam o custo de escrevê-los?

Esta não é uma decisão que você (como desenvolvedor) pode tomar. Na melhor das hipóteses, você pode oferecer uma estimativa do tempo necessário para implementar testes em um determinado projeto, e cabe à gerência decidir se existe uma expectativa suficiente de realmente precisar manter / desenvolver o projeto.

e adiar tudo para o próximo grande refatorador

Se o próximo grande refator é um dado, você realmente precisa escrever os testes.

Mas não adie até que você se depare com grandes mudanças. Meu ponto inicial (não combinando a gravação de testes e a atualização do código) ainda permanece, mas quero acrescentar um segundo ponto aqui: seus desenvolvedores atualmente conhecem melhor o projeto do que em seis meses se passarem esse tempo trabalhando em outros projetos. Aproveite os períodos em que os desenvolvedores já estão aquecidos e não precisam descobrir como as coisas funcionam novamente no futuro.


0

Meus dois centavos:

Aguarde uma grande atualização técnica para o sistema e escreva os testes então ... oficialmente com o suporte do negócio.

Como alternativa, digamos que você seja uma loja SCRUM, sua carga de trabalho é representada pela capacidade e você pode alocar uma% disso para testes de unidade, mas ...

Dizer que você vai voltar e escrever os testes é ingênuo, o que você realmente fará é escrever testes, refatorar e escrever mais testes depois que o refator tornar o código mais testável, e é por isso que é melhor começar com testes como você já sabe, e ...

É melhor para o autor original escrever testes e refatorar o código que eles escreveram anteriormente, não é o ideal, mas, por experiência própria, você deseja que o refator faça com que o código melhore e não seja pior.

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.