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.
fonte
int
valor e retorne algo específico, não é possível escrever um teste de unidade para todos osint
valores possíveis , mas provavelmente faz sentido testar alguns valores úteis que podem desarmar o código, como números negativos (incluindominint
), zeromaxint
, etc. para garantir que alguns casos extremos sejam cobertos.Respostas:
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.
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.
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.
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.
fonte
Dado o código legado 1 , escreva testes de unidade nestas situações:
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].
fonte
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:
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.
fonte
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.
fonte
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:
fonte
Um dos principais objetivos dos testes é garantir que uma alteração não interrompa nada. Este é um processo de três etapas:
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.
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.
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.
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.
fonte
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.
fonte