Eu trabalho em uma pequena empresa como desenvolvedor solo. Sou o único desenvolvedor da empresa. Tenho vários projetos (relativamente) grandes que escrevi e mantenho regularmente, e nenhum deles tem testes para apoiá-los. Ao iniciar novos projetos, muitas vezes me pergunto se devo tentar uma abordagem de TDD. Parece uma boa ideia, mas sinceramente nunca posso justificar o trabalho extra envolvido.
Eu trabalho duro para ter uma visão de futuro em meu design. Sei que certamente um dia outro desenvolvedor precisará manter meu código ou, pelo menos, solucioná-lo. Eu mantenho as coisas o mais simples possível e comento e documento as coisas que seriam difíceis de entender. E o fato é que esses projetos não são tão grandes ou complicados que um desenvolvedor decente teria dificuldade em compreendê-los.
Muitos dos exemplos que eu já vi de testes chegam às minúcias, cobrindo todas as facetas do código. Como sou o único desenvolvedor e estou muito próximo do código em todo o projeto, é muito mais eficiente seguir um padrão de teste de gravação em seguida, manualmente. Também acho que os requisitos e os recursos mudam com frequência suficiente para que a manutenção de testes adicione uma quantidade considerável de atrito em um projeto. Tempo que de outra forma poderia ser gasto resolvendo as necessidades da empresa.
Então, acabo com a mesma conclusão a cada vez. O retorno do investimento é muito baixo.
Ocasionalmente, configurei alguns testes para garantir que escrevi um algoritmo corretamente, como calcular o número de anos que alguém está na empresa com base na data de contratação. Mas, do ponto de vista da cobertura de código, cobri cerca de 1% do meu código.
Na minha situação, você ainda encontraria uma maneira de tornar o teste de unidade uma prática regular ou estou justificado em evitar essa sobrecarga?
ATUALIZAÇÃO: Algumas coisas sobre a minha situação que deixei de fora: Meus projetos são todos aplicativos da Web. Para cobrir todo o meu código, eu teria que usar testes automatizados de interface do usuário, e essa é uma área em que ainda não vejo um grande benefício em relação aos testes manuais.
fonte
Respostas:
Assim? Você não precisa testar tudo . Apenas as coisas relevantes.
Isso é realmente falso. Não é mais eficiente. É realmente apenas um hábito.
O que outros desenvolvedores individuais fazem é escrever um esboço ou estrutura de tópicos, escrever os casos de teste e preencher o esboço com o código final.
Isso é muito, muito eficiente.
Isso é falso também. Os testes não são o problema. As alterações dos requisitos são o arrasto.
Você precisa corrigir os testes para refletir os requisitos. Sejam suas minúcias ou de alto nível; escrito primeiro ou escrito por último.
O código não é feito até que os testes passem. Essa é a verdade universal do software.
Você pode ter um teste de aceitação limitado "aqui está".
Ou você pode fazer alguns testes de unidade.
Ou você pode ter os dois.
Mas não importa o que você faça, sempre há um teste para demonstrar que o software funciona.
Sugiro que um pouco de formalidade e um bom conjunto de ferramentas de teste de unidade tornem esse teste muito mais útil.
fonte
sqrt(-1)
deveria ser um número inteiro, obteria respostas esmagadoras, inclinadas para um lado. O saldo é em torno de "como" e "qual ordem". O fato é que você deve testar. Portanto, escreva os testes primeiro e verifique se eles funcionam.Imagine que você tivesse um conjunto de testes que poderia ser executado em um eyeblink e acenderia uma luz verde ou vermelha. Imagine que este conjunto de testes testou tudo ! Imagine que tudo o que você precisava fazer para executar o conjunto de testes era digitar ^ T. Que poder isso lhe daria?
Você poderia fazer uma alteração no código sem medo de quebrar alguma coisa? Você poderia adicionar um novo recurso sem medo de quebrar um recurso antigo? Você poderia limpar rapidamente o código confuso sem medo de causar danos?
Sim, você poderia fazer todas essas coisas! E o que aconteceria com o seu código ao longo do tempo? Ficaria cada vez mais limpo porque não haveria risco de limpá-lo.
Vamos imaginar que você tivesse uma pequena fada no ombro. Toda vez que você escrevia uma linha de código, a fada adicionava algo ao conjunto de testes que testava se essa linha de código fazia o que se pretendia fazer. Então, a cada par de segundos você poderia pressionar ^ T e ver que a última linha de código que você escreveu funcionava.
Quanto de depuração você acha que faria?
Se isso soa como fantasia, você está certo. Mas a realidade não é muito diferente. Substitua o eyeblink por alguns segundos, e a fada pela disciplina TDD, e você conseguirá.
Digamos que você esteja voltando para um sistema que você construiu há um ano e que esqueceu como criar um dos objetos centrais. Existem testes que criam esse objeto de todas as formas possíveis. Você pode ler esses testes e movimentar sua memória. Precisa chamar uma API? Existem testes que chamam essa API de todas as formas possíveis. Esses testes são pequenos documentos , escritos em um idioma que você entende. Eles são completamente inequívocos. Eles são tão formais que executam. E eles não podem ficar fora de sincronia com o aplicativo!
Não vale o investimento? Só podes estar a brincar comigo! Como alguém pode NÃO querer esse conjunto de testes? Faça um favor a si mesmo e pare de discutir sobre bobagens. Aprenda a fazer bem o TDD e observe quanto mais rápido você vai e quanto mais limpo é o seu código.
fonte
O erro que você está cometendo é que você vê os testes como um investimento de tempo sem retorno imediato. Não necessariamente funciona assim.
Em primeiro lugar, escrever testes realmente o enfoca no que essa parte do seu código precisa fazer.
Em segundo lugar, executá-los revela erros que, de outra forma, surgiriam nos testes.
Em terceiro lugar, executá-los às vezes mostra bugs que, de outra forma, não apareceriam nos testes e, em seguida, realmente te mordiam na produção.
Em quarto lugar, se você acertar um bug em um sistema em execução e criar um teste de unidade para ele, não poderá reintroduzir esse bug posteriormente. Isso pode ser uma grande ajuda. Erros reintroduzidos são comuns e muito irritantes.
Em quinto lugar, se você precisar entregar o código a outra pessoa, uma suíte de testes facilitará sua vida. Além disso, se você ignorou um projeto e o retornou depois de alguns anos, não estará mais tão perto dele e será útil para você também.
Minha experiência sempre foi que, ao longo do desenvolvimento de um projeto, ter testes de unidade decentes sempre tornou o processo mais rápido e mais confiável.
fonte
O pessoal da JUnit (estrutura de teste da unidade Java) tem uma filosofia de que, se for muito simples de testar, não teste . Eu recomendo a leitura das Perguntas frequentes sobre as práticas recomendadas , pois é bastante pragmático.
TDD é um processo diferente de escrever seu software. A premissa básica por trás do teste de unidade é que você passará menos tempo no depurador percorrendo o código e descobrirá mais rapidamente se a alteração do código acidentalmente interrompe outra coisa no sistema. Isso se encaixa no TDD. O ciclo TDD é assim:
O que é menos óbvio sobre a aplicação do TDD é que ele altera a maneira como seu código de gravação . Ao se forçar a pensar em como testar / validar se o código está funcionando, você está escrevendo um código testável. E como estamos falando de testes de unidade, isso geralmente significa que seu código se torna mais modular. Para mim, o código modular e testável é uma grande vitória antecipadamente.
Agora, você precisa testar coisas como propriedades de C #? Imagine uma propriedade definida assim:
A resposta seria "não", não vale a pena testar, porque neste momento você está testando o recurso de idioma. Apenas confie que o pessoal da plataforma C # acertou. Além disso, se falhasse, o que você poderia fazer para corrigi-lo?
Além disso, você descobrirá que existem certas partes do seu código que serão muito difíceis de serem testadas corretamente. Isso significa que não faça isso, mas certifique-se de testar o código que usa / é usado pelo problema complicado:
Acredite ou não, o TDD o ajudará a cair em um ritmo sustentável de desenvolvimento. Não é por causa da mágica, mas sim porque você tem um ciclo de feedback apertado e é capaz de detectar erros realmente burros rapidamente. O custo para corrigir esses erros é essencialmente constante (pelo menos o suficiente para fins de planejamento), porque os pequenos erros nunca se tornam grandes erros. Compare isso com a natureza explosiva dos sprints de purga de depuração / depuração de código.
fonte
Você precisa equilibrar o custo do teste com o custo dos bugs.
Escrever um teste de unidade de 10 linhas para uma função que abre um arquivo, onde a falha é "arquivo não encontrado", é inútil.
Uma função que faz algo complexo para uma estrutura de dados complexa - então obviamente sim.
A parte complicada é intermediária. Mas lembre-se de que o valor real dos testes de unidade não está testando a função específica, está testando as interações complicadas entre eles. Portanto, um teste de unidade que detecta que uma alteração em um bit de código quebra alguma função em um módulo diferente a 1000 linhas de distância vale o seu peso no café.
fonte
Testar é jogar.
Criar um teste é uma aposta de que o custo dos bugs em uma unidade que ocorre e não os captura com esse teste (agora e durante todas as futuras revisões de código) é maior que o custo do desenvolvimento do teste. Esses custos de desenvolvimento de testes incluem itens como folha de pagamento para engenharia de teste, tempo de colocação no mercado, custos de oportunidade perdidos por não codificar outras coisas e etc.
Como qualquer aposta, às vezes você ganha, às vezes perde.
Em algum momento, o software atrasado, com muito menos erros, ganha com as coisas rápidas, mas com erros, que chegam ao mercado primeiro. Às vezes o oposto. Você precisa examinar as estatísticas em seu campo específico e quanto a gerência deseja jogar.
Alguns tipos de bugs podem ser tão improváveis de serem executados ou eliminados de qualquer teste de sanidade inicial, que não valem estatisticamente o tempo necessário para criar testes específicos adicionais. Mas, às vezes, o custo de um bug é tão grande (médico, nuclear etc.) que uma empresa deve fazer uma aposta perdida (semelhante à compra de seguro). Muitos aplicativos não têm um custo de falha tão alto e, portanto, não precisam de uma cobertura de seguro antieconômica mais alta. Outros fazem.
fonte
Meu conselho é testar apenas o código que você deseja que funcione corretamente.
Não teste o código que você deseja que seja um buggy e cause problemas para você no futuro.
fonte
TDD e teste de unidade não são a mesma coisa.
Você pode escrever código e adicionar testes de unidade posteriormente. Isso não é TDD e é muito trabalho extra.
TDD é a prática de codificação em um loop de luz vermelha. Luz verde. Refatorar iterações.
Isso significa escrever testes para o código que ainda não existe, assistir os testes falharem, corrigir o código para fazer com que os testes funcionem e depois tornar o código "correto". Isso geralmente economiza seu trabalho
Uma das vantagens do TDD é que ele reduz a necessidade de pensar em curiosidades. Coisas como erros pontuais desaparecem. Você não precisa procurar na documentação da API para descobrir se a lista retornada começa em 0 ou 1, basta fazê-lo.
fonte
Eu trabalhei em um sistema onde testamos quase tudo. As execuções notáveis dos testes foram o código de saída PDF e XLS.
Por quê? Fomos capazes de testar as partes que coletaram os dados e construímos o modelo usado para criar a saída. Também fomos capazes de testar as partes que descobriram quais partes do modelo iriam para os arquivos PDF. Não foi possível testar se o PDF parecia bom porque isso era totalmente subjetivo. Não foi possível testar se todas as partes de um PDF eram legíveis para um usuário comum, porque isso também era subjetivo. Ou se a escolha entre gráficos de barras e de pizza estava correta para o conjunto de dados.
Se a saída for subjetiva, há poucos testes de unidade, você pode fazer o que vale o esforço.
fonte
Para muitas coisas, um 'teste de gravação e depois manualmente' não leva mais tempo do que escrever alguns testes. A economia de tempo advém da capacidade de executar novamente esses testes a qualquer momento.
Pense nisso: Se você tem alguma cobertura recurso decente com seus testes (não confundir com cobertura de código), e vamos dizer que você tem 10 características - clicar em um botão significa que você tem cerca de, 10 yous fazendo re-seus testes ... enquanto você se senta e bebe seu café.
Você também não precisa testar as minúcias. Você pode escrever testes de integração que abrangem seus recursos, se você não quiser obter detalhes minuciosos ... IMO, alguns testes de unidade são detalhados demais testando o idioma e a plataforma, e não o código.
TL; DR Nunca é realmente apropriado porque os benefícios são bons demais.
fonte
Duas respostas muito boas que encontrei estão aqui:
As justificativas para evitar a sobrecarga percebida:
Você não gostaria de deixar um ótimo produto do seu lado como prova da qualidade do seu trabalho? Falando em termos egoístas, não é melhor para você o que você faz?
fonte
Desenvolvedores profissionais escrevem testes de unidade porque, a longo prazo, economizam tempo. Você testará seu código mais cedo ou mais tarde e, se não o fizer, seus usuários, e se precisar corrigir bugs mais tarde, eles serão mais difíceis de corrigir e terão mais efeitos negativos.
Se você está escrevendo código sem testes e não possui bugs, tudo bem. Não acredito que você possa escrever um sistema não trivial com zero bugs, portanto, presumo que você o esteja testando de uma maneira ou de outra.
Os testes de unidade também são cruciais para evitar regressões quando você modifica ou refatora o código mais antigo. Eles não provam que sua alteração não quebrou o código antigo, mas lhe dão muita confiança (desde que sejam aprovados :))
Não voltaria a escrever um lote inteiro de testes para o código que você já enviou, mas da próxima vez que precisar modificar um recurso, sugiro que tente escrever testes para esse módulo ou classe, obtenha uma cobertura de até 70% + antes de aplicar as alterações. Veja se isso ajuda você.
Se você tentar e honestamente dizer que não ajudou, é justo o suficiente, mas acho que existem evidências suficientes da indústria de que elas ajudam a fazer com que valha a pena ao testar a abordagem.
fonte
Parece que a maioria das respostas é pró-TDD, mesmo que a pergunta não estivesse sendo feita sobre TDD, mas sobre testes de unidade em geral.
Não existe uma regra completamente objetiva por trás do que fazer o teste de unidade ou não. Mas há algumas vezes em que parece que muitos programadores não fazem teste de unidade:
Dependendo da sua filosofia de POO, você pode criar métodos privados para dissociar rotinas complexas de seus métodos públicos. Geralmente, os métodos públicos devem ser chamados em muitos lugares diferentes e usados com freqüência, e os métodos privados são realmente chamados apenas por um ou dois métodos públicos em uma classe ou módulo para algo muito específico. Geralmente é suficiente escrever testes de unidade para métodos públicos, mas não os métodos privados subjacentes que fazem parte da mágica acontecer. Se algo der errado com um método privado, seus testes de unidade de método público devem ser bons o suficiente para detectar esses problemas.
Muitos programadores novos contrariam isso quando aprendem a testar pela primeira vez e pensam que precisam testar todas as linhas que estão sendo executadas. Se você estiver usando uma biblioteca externa e sua funcionalidade for bem testada e documentada por seus autores, geralmente não faz sentido testar a funcionalidade específica em testes de unidade. Por exemplo, alguém pode escrever um teste para garantir que seu modelo ActiveRecord persista o valor correto de um atributo com um retorno de chamada "before_save" no banco de dados, mesmo que esse comportamento já tenha sido exaustivamente testado no Rails. O (s) método (s) que o retorno de chamada está chamando, talvez, mas não o próprio comportamento do retorno de chamada. Quaisquer problemas subjacentes às bibliotecas importadas seriam melhor revelados através de testes de aceitação, em vez de testes de unidade.
Ambos podem ser aplicados, esteja você fazendo TDD ou não.
fonte
Ken, eu e muitos outros desenvolvedores por aí chegamos à mesma conclusão que você várias vezes ao longo de nossas carreiras.
A verdade que acredito que você encontrará (como muitas outras) é que o investimento inicial em escrever testes para o seu aplicativo pode parecer assustador, mas se for bem escrito e direcionado para as partes corretas do seu código, eles podem realmente economizar uma tonelada de tempo.
Meu grande problema foi com as estruturas de teste disponíveis. Eu realmente nunca senti que eles eram o que eu estava procurando, então apenas criei minha própria solução muito simples. Isso realmente ajudou a me trazer para o "lado negro" dos testes de regressão. Compartilharei um pseudo trecho básico do que fiz aqui e espero que você encontre uma solução que funcione para você.
A única parte complicada depois disso é descobrir qual o nível de granularidade que você acha que é o melhor "retorno do investimento" para qualquer projeto que esteja realizando.
Construir um catálogo de endereços obviamente exigirá muito menos testes do que um mecanismo de pesquisa empresarial, mas os fundamentos realmente não mudam.
Boa sorte!
fonte