O desenvolvimento controlado por teste (TDD) é grande hoje em dia. Costumo vê-lo recomendado como uma solução para uma ampla gama de problemas aqui no Programmers SE e em outros locais. Eu me pergunto por que isso funciona.
Do ponto de vista da engenharia, isso me intriga por duas razões:
- A abordagem "teste de gravação + refatoração até aprovação" parece incrivelmente anti-engenharia. Se os engenheiros civis usassem essa abordagem para a construção de pontes ou os projetistas de carros, por exemplo, eles remodelariam suas pontes ou carros a um custo muito alto, e o resultado seria uma bagunça remendada, sem arquitetura bem pensada . A diretriz "refatorar até a aprovação" é frequentemente tomada como um mandato para esquecer o projeto arquitetônico e fazer o que for necessário para cumprir o teste; em outras palavras, o teste, e não o usuário, define o requisito. Nesta situação, como podemos garantir boas "ilidades" nos resultados, isto é, um resultado final que não é apenas correto, mas também extensível, robusto, fácil de usar, confiável, seguro, seguro, etc.? Isso é o que a arquitetura geralmente faz.
- O teste não pode garantir que um sistema funcione; só pode mostrar que não. Em outras palavras, o teste pode mostrar que um sistema contém defeitos se falhar em um teste, mas um sistema que passa em todos os testes não é mais seguro do que um sistema que os falha. A cobertura, a qualidade e outros fatores são cruciais aqui. As falsas sensações de segurança que um resultado "totalmente verde" produz para muitas pessoas foram relatadas nas indústrias civil e aeroespacial como extremamente perigosas, porque podem ser interpretadas como "o sistema está bom", quando realmente significa "o sistema está tão bom como nossa estratégia de teste ". Freqüentemente, a estratégia de teste não é verificada. Ou quem testa os testes?
Em resumo, estou mais preocupado com o bit "acionado" no TDD do que com o bit "teste". Teste é perfeitamente bom; o que eu não entendo é dirigir o design ao fazê-lo.
Gostaria de ver respostas contendo razões pelas quais o TDD em engenharia de software é uma boa prática e por que os problemas que expliquei acima não são relevantes (ou não são relevantes o suficiente) no caso de software. Obrigado.
Respostas:
Eu acho que há um equívoco aqui. No design de software, o design é muito próximo ao produto. Na engenharia civil, arquitetura, o design é dissociado do produto real: existem projetos que mantêm o design, que são materializados no produto final e são separados por grandes quantidades de tempo e esforço.
TDD está testando o design. Mas todo projeto de carro e construção também é testado. As técnicas de construção são primeiro calculadas, depois testadas em menor escala, depois testadas em maior escala, antes de serem construídas em um edifício real. Quando eles inventaram as vigas H e a carga, por exemplo, tenha certeza de que isso foi tentado e tentado novamente antes que eles realmente construíssem a primeira ponte com ela.
Projetos de carros também são testados, projetando protótipos e, sim, certamente, ajustando coisas que não são exatamente corretas, até que atenda às expectativas. Parte desse processo, porém, é mais lenta, porque, como você disse, você não pode mexer muito com o produto. Mas todo redesenho de um carro baseia-se nas experiências aprendidas com os anteriores, e todo edifício tem cerca de mil anos de fundamentos sobre a importância do espaço, luz, isolamento, resistência, etc. Detalhes são alterados e aprimorados, tanto nos edifícios e em redesenhos para os mais novos.
Além disso, as peças são testadas. Talvez não exatamente do mesmo estilo que o software, mas as peças mecânicas (rodas, dispositivos de ignição, cabos) geralmente são medidas e submetidas a estresse para saber se os tamanhos estão corretos, que não há anormalidades, etc. Eles podem ser raios X ou laser. medidos, eles batem nos tijolos para identificar os quebrados, eles podem ser realmente testados em alguma configuração ou outra, ou desenham uma representação limitada de um grande grupo para realmente colocá-lo à prova.
Essas são todas as coisas que você pode implementar com o TDD.
E, de fato, o teste não é garantia. Os programas falham, os carros quebram e os prédios começam a fazer coisas engraçadas quando o vento sopra. Mas ... 'segurança' não é uma questão booleana. Mesmo quando você nunca pode incluir tudo, ser capaz de cobrir - digamos - 99% das eventualidades é melhor do que cobrir apenas 50%. Não testar e depois descobrir que o aço não se estabilizou bem e é quebradiço e quebra ao primeiro toque de um martelo quando você acaba de montar sua estrutura principal é um simples desperdício de dinheiro. O fato de haver outras preocupações que ainda podem prejudicar o edifício não torna menos estúpido permitir que uma falha facilmente evitável atrapalhe seu projeto.
Quanto à prática do TDD, isso é uma questão de equilíbrio. O custo de fazê-lo de uma maneira (por exemplo, não testar e depois recolher as peças mais tarde), versus o custo de fazê-lo de outra maneira. É sempre um equilíbrio. Mas não pense que outros processos de design não tenham testes e TDD em vigor.
fonte
Na IMO, a maioria das histórias de sucesso do TDD é falsa e apenas para fins de marketing. Pode haver muito pouco sucesso com isso, mas apenas para pequenas aplicações. Estou trabalhando em um grande aplicativo silverlight onde os princípios TDD são usados. O aplicativo tem centenas de testes, mas ainda não é estável. Várias partes do aplicativo não podem ser testadas devido às complexas interações do usuário. Testes resultantes com muitas zombarias e código difícil de entender.
Inicialmente, quando tentamos o TDD, tudo parece bom. Consegui escrever muitos testes e zombar das partes difíceis para um teste de unidade. Depois de ter uma quantidade razoável de código e uma alteração na interface ser necessária, você estará ferrado. Muitos testes precisam ser corrigidos e você reescreverá mais testes do que a alteração real no código.
Peter Norvig Explica sua visão sobre TDD no livro Coders At Work.
fonte
well, you haven't done TDD right!
O Design orientado a teste funciona para mim pelos seguintes motivos:
É uma forma executável da especificação.
Isso significa que você pode ver nos casos de teste:
Você escreve a vista de fora primeiro.
Frequentemente código é escrito de uma forma onde você primeiro resolver o problema, e então você pensa de como o código que você escreveu apenas está a ser chamado. Isso frequentemente fornece uma interface estranha, porque é frequentemente mais fácil "simplesmente adicionar uma bandeira", etc. Isso dará uma melhor modularidade, pois o código será escrito de acordo com a interface de chamada, e não o contrário.
Isso geralmente resultará em código mais limpo, o que exige menos documentação explicativa.
Você é feito mais rápido
Como você tem a especificação no formato executável, está pronto quando o conjunto completo de testes passa. Você pode adicionar mais testes ao esclarecer as coisas em um nível mais detalhado, mas como princípio básico, você tem um indicador muito claro e visível do progresso e quando terminar.
Isso significa que você pode dizer quando o trabalho é necessário ou não (isso ajuda a passar no teste) e você acaba precisando fazer menos.
Para aqueles que consideram útil, recomendamos que você use o TDD para sua próxima rotina de biblioteca. Configure lentamente uma especificação executável e faça o código passar nos testes. Quando concluída, a especificação executável está disponível para todos que precisam ver como chamar a biblioteca.
Estudo recente
"Os resultados dos estudos de caso indicam que a densidade de defeitos de pré-lançamento dos quatro produtos diminuiu entre 40% e 90% em relação a projetos semelhantes que não usavam a prática de TDD. Subjetivamente, as equipes experimentaram um aumento de 15 a 35% tempo de desenvolvimento inicial após a adoção do TDD ". ~ Resultados e experiências de 4 equipes industriais
fonte
O processo de criação de software não é o processo de escrever o código. Nenhum projeto de software deve começar sem um plano de 'amplo escopo' primeiro. Assim como um projeto de ponte entre duas margens de um rio precisa desse plano primeiro.
A abordagem TDD se relaciona (principalmente) ao teste de unidade - pelo menos é assim que as pessoas pensam sobre isso - que está criando os bits mais baixos de código de software. Quando todos os recursos e comportamentos já foram definidos e sabemos realmente o que queremos alcançar.
Na engenharia estrutural, parece um pouco com isso:
Para testar se o software funciona como um todo, projetamos outros tipos de testes, como testes de usabilidade, testes de integração e testes de aceitação. Eles também devem ser definidos antes que o trabalho real de escrever o código seja iniciado e sejam executados após os testes de unidade ficarem verdes.
Consulte o modelo V: http://en.wikipedia.org/wiki/V-Model_%28software_development%29
Vamos ver como isso funcionaria para uma ponte:
Um governo local diz a uma empresa de construção de pontes: "Precisamos de uma ponte para conectar esses dois pontos. A ponte precisa permitir n quantidade de tráfego por hora e estar pronta para 21 de dezembro de 2012 '- essa é uma definição de A empresa não receberá o valor total (ou qualquer) dinheiro, se não conseguir passar no teste.
O gerenciamento da empresa decide o cronograma do projeto. Eles montam equipes de trabalho e estabelecem metas para cada equipe. Se as equipes não atingirem esses objetivos - a ponte não será construída no prazo. No entanto - há algum nível de flexibilidade aqui. Se uma das equipes tiver alguns problemas, a empresa poderá compensar isso alterando os requisitos, alterando subcontratados, contratando mais pessoas etc. para que todo o projeto ainda atenda à meta estabelecida no ponto 1.
Dentro de uma equipe responsável por projetar componentes de ponte específicos, parece com o exemplo que eu dei acima. Às vezes, a solução é óbvia, porque temos um grande conhecimento sobre a construção de pontes (é como usar uma biblioteca bem testada no desenvolvimento de software - você apenas supõe que ela funcione como anunciado). Às vezes, você precisa criar vários designs e testá-los para escolher o melhor. Ainda assim, os critérios sobre os quais o componente é testado são conhecidos antecipadamente.
fonte
Na minha opinião, o TDD funciona porque
Especificamente nos pontos que você levanta
fonte
TL; DR
A programação ainda é uma atividade de design, não é de construção. Escrever testes de unidade após o fato apenas confirma que o código faz o que faz, e não que faz algo útil. As falhas no teste são o valor real, pois permitem que você cometa erros mais cedo.
Code Is Design
No capítulo 7 do PPP, "Tio Bob" fala diretamente sobre esse assunto. No início do capítulo, ele faz referência a um excelente artigo de Jack Reeves, no qual propõe que o código é design (o link vai para uma página que reúne todos os três artigos sobre o assunto).
O que é interessante sobre esse argumento é que ele ressalta, diferentemente de outras disciplinas de engenharia em que a construção é uma atividade muito cara, a construção do software é relativamente livre (clique em compilar no seu IDE e você tiver o seu software construído). Se você visualizar a escrita de código como uma atividade de design em vez de uma atividade de construção, o ciclo de refator vermelho-verde é basicamente um exercício de design. Seu design evolui à medida que você escreve testes, o código para satisfazê-los e refatora para integrar o novo código ao sistema existente.
TDD como especificação
Os testes de unidade que você escreve para TDD são uma tradução direta da especificação conforme você os entende. Ao escrever um código que satisfaça minimamente sua especificação (faz com que seus testes fiquem verdes), todo o código que você escreveu está lá para uma finalidade específica. O cumprimento ou não desse objetivo é validado por um teste repetitivo.
Gravar testes na funcionalidade
Um erro comum no teste de unidade ocorre quando você escreve os testes após o código, e acaba testando se o código faz o que faz. Em outras palavras, você verá testes como este
Embora eu ache que esse código possa ser útil (verifique se alguém não fez algo obsceno com uma propriedade simples). Não serve para validar uma especificação. E como você disse, escrever esse tipo de teste leva apenas até o momento.
Enquanto o verde é bom, o valor está no vermelho Eu tive meu primeiro momento "aha" verdadeiro no TDD, quando tive uma falha inesperada no teste. Eu tinha um conjunto de testes para uma estrutura que estava construindo. Adicionando um novo recurso, escrevi um teste para ele. Em seguida, escreveu o código para fazer o teste passar. Compilar, testar ... ficou verde no novo teste. Mas também recebi um vermelho em outro teste que não esperava ficar vermelho.
Olhando para o fracasso, dou um suspiro de alívio, porque duvido que tenha pegado o bug por algum tempo se não tivesse feito esse teste. E foi um bug MUITO desagradável de ter. Felizmente, fiz o teste e ele me disse exatamente o que precisava fazer para corrigir o bug. Sem o teste, eu continuaria construindo meu sistema (com o bug infectando outros módulos que dependiam desse código) e, quando o bug foi descoberto, teria sido uma tarefa importante corrigi-lo adequadamente.
O verdadeiro benefício do TDD é que ele nos permite fazer alterações com abandono imprudente. É como uma rede de segurança para programação. Pense no que aconteceria se um trapezista cometer um erro e cair. Com a rede, é um erro embaraçoso. Sem, é uma tragédia. Da mesma forma, o TDD evita que você transforme erros idiotas em desastres que matam projetos.
fonte
Você não encontrará ninguém que defenda o Test Driven Development, ou mesmo o Test Driven Design (eles são diferentes), que afirma que os testes provam aplicativos. Então vamos apenas chamar isso de homem de palha e pronto.
Você não encontrará ninguém que não goste ou não esteja impressionado com o TDD que diz que os testes são uma perda de tempo e esforço. Embora os testes não provem aplicativos, eles são bastante úteis para encontrar erros.
Com essas duas coisas, nenhum dos lados está fazendo algo diferente no que diz respeito à realização de testes no software. Ambos estão fazendo testes. Ambos confiam nos testes para encontrar o maior número possível de erros e usam testes para verificar se um programa de software está funcionando tão bem quanto pode ser descoberto no momento. Ninguém com meia pista vende software sem teste e ninguém com meia pista espera que o teste processe o código que eles vendem completamente sem erros.
Portanto, a diferença entre TDD e não-TDD não é que os testes estão sendo feitos. A diferença está em quando os testes são escritos. Nos testes TDD são escritos ANTES do software. Em testes não TDD, são escritos após ou em conjunto com o software.
O problema que vi em relação a este último é que o teste tende a ter como alvo o software que está sendo escrito mais do que o resultado ou especificação desejada. Mesmo com a equipe de testes sendo separada da equipe de desenvolvimento, a equipe de testes tende a olhar para o software, brincar com ele e escrever testes direcionados a ele.
Uma coisa que tem sido notada repetidamente por aqueles que estudam o sucesso do projeto é a frequência com que um cliente define o que deseja, o pessoal do desenvolvimento foge e escreve algo e, quando volta ao cliente dizendo "pronto" acaba por ser total e completamente NÃO o que o cliente pediu. "Mas passa em todos os testes ..."
O objetivo do TDD é quebrar esse "argumento circular" e fornecer base para os testes que testam o software que não é o próprio software. Os testes são escritos para direcionar o comportamento que o "cliente" deseja. O software é então escrito para passar nesses testes.
O TDD é parte da solução destinada a resolver esse problema. Não é o único passo que você dá. Outras coisas que você precisa fazer é garantir que haja mais comentários dos clientes e com mais frequência.
Na minha experiência, porém, o TDD é uma coisa muito difícil de implementar com sucesso. É difícil obter testes escritos antes que exista um produto, porque muitos testes automatizados exigem ter algo para brincar para que o software de automação funcione corretamente. Também é difícil conseguir desenvolvedores que não estão acostumados a testes de unidade para fazer isso. Repetidas vezes, eu disse às pessoas da minha equipe que escrevessem os testes PRIMEIRO. Na verdade, nunca consegui um para fazê-lo. No final, as restrições de tempo e a política destruíram todos os esforços, para que nem sequer realizássemos testes de unidade. É claro que isso levou inevitavelmente ao acoplamento acidental e severo do design, de modo que, mesmo se quiséssemos, agora seria proibitivamente oneroso de implementar. Evitar ISSO é o que o TDD fornece para os desenvolvedores.
fonte
Design primeiro
TDD não é uma desculpa para pular o design. Eu já vi muitos pularem na onda "ágil" porque eles poderiam começar a codificar imediatamente. O verdadeiro ágil fará com que você codifique as estatísticas muito mais rapidamente do que as boas práticas de engenharia (de outro campo) que inspiraram o processo em cascata.
Mas teste cedo
Quando se diz que o teste está conduzindo o design, significa simplesmente que é possível usá-lo muito cedo na fase de design, muito antes de sua conclusão. A realização desses testes influenciará fortemente seu design, desafiando as áreas cinzentas e colocando-o contra o mundo real muito antes de o produto ser concluído. forçando você a voltar ao design e ajustá-lo para levar isso em consideração.
Teste e design ... um e o mesmo
Na minha opinião, o TDD simplesmente traz o teste para ser parte integrante do design, em vez de algo feito no final para validá-lo. À medida que você começa a usar o TDD, cada vez mais, você começa a pensar em como destruir / quebrar seu sistema ao projetá-lo. Pessoalmente, nem sempre faço meus testes primeiro. Certamente, eu faço os testes óbvios (unitários) em uma interface, mas os ganhos reais advêm dos testes de integração e especificação que eu crio quando penso em uma maneira nova e criativa que esse design pode quebrar. Assim que penso em uma maneira, codifico um teste e vejo o que acontece. Às vezes, posso viver com a conseqüência; nesse caso, movo o teste em um projeto separado que não faz parte da compilação principal (pois continuará a falhar).
Então quem dirige o show?
No TDD, o acionado aqui significa simplesmente que seus testes influenciam tão fortemente o seu design que é possível sentir que eles estão realmente conduzindo-o. No entanto, para-se nisso, e aqui eu entendo suas preocupações, é um pouco assustador ... quem dirige o show?
Você está dirigindo, não os testes. Os testes existem para que, à medida que você avança, obtenha um bom nível de confiança no que criou, permitindo que você desenvolva ainda mais o conhecimento de que repousa em bases sólidas.
sólido desde que os testes sejam sólidos
Exatamente , daí o impulsionado no TDD. Não são tanto os testes que estão conduzindo a coisa toda, mas eles terão uma influência tão profunda sobre como você faz as coisas, sobre como você projeta e pensa seu sistema que delegará grande parte do seu processo de pensamento em testes e em troca eles terão uma profunda influência no seu design.
sim, mas se eu fizer isso com a minha ponte th ....
pare aí mesmo ... a engenharia de software é MUITO diferente de qualquer outra prática de engenharia existente. De fato, a engenharia de software tem muito mais em comum com a literatura. Pode-se pegar um livro acabado, extrair quatro capítulos e escrever dois novos capítulos para substituí-los. Colá-los novamente no livro e você ainda tem um bom livro. Com bons testes e software, você pode extrair qualquer parte do seu sistema e substituí-lo por outro, e o custo de fazer isso não é muito maior do que o estava criando em primeiro lugar. De fato, se você fez seus testes e permitiu que eles influenciassem seu design o suficiente, pode muito bem ser mais barato do que criá-lo, pois você terá um certo nível de confiança de que essa substituição não interromperá o que os testes estão cobrindo.
Se é tão bom, como é que nem sempre funciona?
Porque o teste requer uma mentalidade MUITO diferente da construção. Nem todo mundo é capaz de voltar e voltar, de fato, algumas pessoas não serão capazes de criar testes apropriados simplesmente porque não conseguem pensar em destruir sua criação. Isso produzirá projetos com poucos testes ou testes suficientes para atingir as métricas desejadas (a cobertura do código vem à mente). Eles farão testes de caminho felizes e testes de exceção, mas esquecerão os casos de canto e as condições de contorno.
Outros apenas confiarão nos testes que abandonam o projeto parcial ou totalmente. Cada membro que faz isso se integra um ao outro. O design é, acima de tudo, uma ferramenta de comunicação, que colocamos em jogo para dizer que é aqui que eu estarei, esboços que dizem que é aqui que as portas e janelas estarão. Sem isso, seu software está condenado, independentemente de quantos testes você fizer. Integração e mesclagem sempre serão dolorosas e não terão testes nos níveis mais altos de abstrações.
Para essas equipes, TDD pode não ser o caminho a percorrer.
fonte
Com o TDD, você tende a não escrever código que não seja fácil ou rápido de testar. Isso pode parecer algo pequeno, mas pode ter um efeito profundo em um projeto, pois afeta a facilidade de refatorar, testar, reproduzir bugs com testes e verificar correções.
Também é mais fácil para um novo desenvolvedor do projeto se atualizar quando você tiver um código fatorado melhor suportado por testes.
fonte
Eu tenho pensado muito sobre isso, apesar de eu não praticar tanto o TDD. Parece haver uma correlação positiva (forte?) Entre a qualidade do código e o seguinte TDD.
1) Minha primeira conclusão é que, principalmente (isso não é devido ao TDD adicionando "melhor qualidade" ao código (como tal)), é mais como o TDD ajuda a eliminar as piores partes e hábitos e, assim, indiretamente, aumentar a qualidade.
Eu até defenderia que não é o teste em si - é o processo de escrever esses testes. É difícil escrever testes para um código incorreto e vice-versa. E manter isso na parte de trás da cabeça durante a programação elimina muitos códigos ruins.
2) Outro ponto de vista (isso está ficando filosófico) é seguir os hábitos mentais do mestre. Você não aprende a se tornar um mestre seguindo seus "hábitos externos" (como uma barba longa é boa), deve aprender seus modos internos de pensar, e isso é difícil. E, de alguma forma, fazer programadores (iniciantes) seguirem o TDD, alinhar suas formas de pensar mais próximas às do mestre.
fonte
Você parece ter um equívoco sobre refatoração e TDD.
Portanto, você não pode refatorar o código até que ele passe.
E o TDD, especificamente o teste de unidade (que considero a melhoria principal, já que outros testes me parecem bastante plausíveis), não se trata de redesenhar um componente até que ele funcione. Trata-se de projetar um componente e trabalhar na implementação até que o componente funcione conforme projetado.
Também é importante entender, que o teste de unidade é sobre unidades de teste . Devido à tendência de sempre escrever muitas coisas do zero, é importante testar essas unidades. Um engenheiro civil já conhece as especificações das unidades que ele usa (os diferentes materiais) e pode esperar que funcionem. Essas são duas coisas que geralmente não se aplicam aos engenheiros de software, e é muito pró-engenharia testar as unidades antes de usá-las, porque significa usar componentes testados e de alta qualidade.
Se um engenheiro civil teve a idéia de usar um novo tecido de fibra para fazer um telhado para cobrir um estádio, seria de esperar que ele o testasse como uma unidade, ou seja, defina as especificações necessárias (por exemplo, peso, permeabilidade, estabilidade etc.) e depois teste e refine-o até encontrá-los.
É por isso que o TDD funciona. Como se você criar um software de unidades testadas, as chances são muito melhores de funcionar. Quando você as conecta e, se não, pode esperar que o problema esteja no seu código de cola, supondo que seus testes tenham uma boa cobertura.
editar:
Refatoração significa: nenhuma alteração na funcionalidade. Um ponto de escrever o teste de unidade é garantir que a refatoração não quebre o código. Portanto, o TDD deve garantir que a refatoração não tenha efeitos colaterais.
A granularidade não é um assunto de perspectiva, porque, como eu disse, a unidade testa unidades de teste e não sistemas, nos quais a granularidade é exatamente definida.
O TDD incentiva uma boa arquitetura. Requer que você defina e implemente especificações para todas as suas unidades, forçando-as a projetá-las antes da implementação, o que é exatamente o contrário do que você pensa. O TDD determina a criação de unidades, que podem ser testadas individualmente e, portanto, completamente dissociadas.
TDD não significa que eu faça um teste de software com código espaguete e mexa a massa até que ela passe.
Ao contrário da engenharia civil, na engenharia de software um projeto geralmente evolui constantemente. Na engenharia civil, você tem a exigência de construir uma ponte na posição A, que pode transportar x toneladas e é larga o suficiente para n veículos por hora.
Na engenharia de software, o cliente pode basicamente decidir, a qualquer momento (possivelmente após a conclusão), que ele quer uma ponte de dois andares e que ela esteja conectada à rodovia mais próxima e que gostaria que fosse uma ponte de elevação, porque sua empresa recentemente começou a usar navios à vela.
Os engenheiros de software têm a tarefa de alterar os projetos. Não porque seus projetos são falhos, mas porque esse é o modus operandi. Se o software for bem projetado, ele poderá ser reprojetado em alto nível, sem precisar reescrever todos os componentes de baixo nível.
TDD é sobre a construção de software com componentes individualmente dissociados e altamente dissociados. Bem executado, ajudará você a responder a alterações nos requisitos significativamente mais rápidas e seguras do que sem.
O TDD adiciona requisitos ao processo de desenvolvimento, mas não proíbe outros métodos de garantia de qualidade. É verdade que o TDD não oferece a mesma segurança que a verificação formal, mas, novamente, a verificação formal é extremamente confortável e impossível de usar no nível do sistema. E ainda assim, se você quiser, poderá combinar os dois.
O TDD também abrange outros testes que não os testes de unidade, que são executados no nível do sistema. Acho isso fácil de explicar, mas difícil de executar e difícil de medir. Além disso, eles são bastante plausíveis. Embora eu veja absolutamente a necessidade deles, não os valorizo realmente como idéias.
No final, nenhuma ferramenta realmente resolve um problema. As ferramentas apenas facilitam a solução de um problema. Você pode perguntar: Como um cinzel vai me ajudar com uma ótima arquitetura? Bem, se você planeja fazer paredes retas, tijolos retos são úteis. E sim, é verdade, se você der essa ferramenta a um idiota, ele provavelmente a enfiará no pé, mas isso não é culpa do cinzel, por mais que não seja uma falha do TDD que dê segurança falsa aos novatos, quem não escreve bons testes.
Então, no final das contas, pode-se dizer que o TDD funciona muito melhor do que nenhum TDD.
fonte
Não gosto do seu dizer 'o teste, e não o usuário, define o requisito'. Eu acho que você está considerando apenas testes de unidade no TDD, enquanto também abrange testes de integração.
Além de testar as bibliotecas que compõem a base do software, escreva os testes que cobrem as interações que seus usuários mantêm com o software / site / o que for. Eles vêm diretamente dos usuários, e bibliotecas como pepino (http://cukes.info) podem até permitir que seus usuários escrevam os testes eles mesmos, em linguagem natural.
O TDD também incentiva a flexibilidade do código - se você passar para sempre projetando a arquitetura de algo, será incrivelmente difícil fazer essas alterações posteriormente, se necessário. Comece escrevendo alguns testes e depois escreva um pequeno código que passe nesses testes. Adicione mais testes, adicione mais código. Se você precisar alterar radicalmente o código, seus testes ainda serão válidos.
E ao contrário de pontes e carros, uma única peça de software pode sofrer grandes mudanças durante sua vida útil, e fazer refactoring complexo sem ter provas escritas primeiro está apenas pedindo para ter problemas.
fonte
Eu acho que você está se aproximando do primeiro ponto do ângulo errado.
Do ponto de vista teórico, estamos provando que algo funciona checando os pontos de falha. Esse é o método usado. Pode haver muitas outras maneiras de provar que algo está funcionando, mas o TDD se estabeleceu devido à simplicidade de sua abordagem bit a bit: se não quebrar, funciona.
Na prática, isso se traduz francamente em: agora podemos passar para a próxima coisa (depois de aplicarmos o TDD com sucesso para satisfazer todos os predicados). Se você abordar o TDD dessa perspectiva, não se trata de "escrever testes + refatorar até passar", é mais uma questão de concluir isso, agora estou focando totalmente no próximo recurso como a coisa mais importante agora .
Pense em como isso se aplica à engenharia civil. Estamos construindo um estádio que pode abrigar uma audiência pública de 150000 pessoas. Depois de provarmos que a integridade estrutural do estádio é sólida, satisfazemos a segurança primeiro . Agora, podemos nos concentrar em outras questões que se tornam imediatamente importantes, como banheiros, bancas de alimentos, assentos, etc ... tornando a experiência do público mais agradável. Isso é uma simplificação excessiva, pois há muito mais no TDD, mas o ponto crucial é que você não faz a melhor experiência possível para o usuário se estiver se concentrando em recursos novos e interessantes e mantendo a integridade ao mesmo tempo. Você consegue pela metade nos dois casos. Quero dizer, como você pode saber exatamente comomuitos lavatórios e onde você deve colocar para 150000 pessoas? Eu raramente vi estádios desabarem na minha vida, mas tive que esperar na fila durante o intervalo em tantas ocasiões. Isso indica que o problema do lavatório é sem dúvida mais complexo e, se os engenheiros puderem gastar menos tempo com segurança, poderão finalmente resolver o problema do lavatório.
Seu segundo ponto é irrelevante, porque já concordamos que os absolutos são um esforço tolo e porque Hank Moody diz que eles não existem (mas não consigo encontrar uma referência para isso).
fonte
O TDD na engenharia de software é uma boa prática, da mesma forma que o tratamento de erros em aplicativos é uma boa prática, além de registro e diagnóstico (embora faça parte do tratamento de erros).
O TDD não deve ser usado como uma ferramenta para reduzir o desenvolvimento de software na codificação de tentativa e erro. Ainda assim, a maioria dos programadores observa os logs de tempo de execução, observa exceções no depurador ou usa outros sinais de falha / sucesso durante sua fase de desenvolvimento, que consiste em codificar / compilar / executar o aplicativo - o dia inteiro.
O TDD é apenas uma maneira de formalizar e automatizar essas etapas para torná-lo como desenvolvedor mais produtivo.
1) Você não pode comparar a engenharia de software à construção de ponte; a flexibilidade na construção de ponte não é nem de longe a de projetar um programa de software. Construir a ponte é como escrever o mesmo programa repetidamente em uma máquina com perdas. As pontes não podem ser duplicadas e reutilizadas como o software. Cada ponte é única e deve ser fabricada. O mesmo vale para carros e outros modelos.
A coisa mais difícil na engenharia de software é reproduzir falhas, quando uma ponte falha geralmente é muito fácil determinar o que deu errado e, em teoria, é fácil reproduzir a falha. Quando um programa de computador falha, pode ser uma cadeia complexa de eventos que levou o sistema a um estado defeituoso e pode ser muito difícil determinar onde está o erro. O teste de TDD e de unidade facilita o teste da robustez dos componentes, bibliotecas e algoritmos de software.
2) Usar testes de unidade fracos e casos de teste rasos que não forçam o sistema a criar falso senso de confiança é apenas uma prática ruim. Ignorar a qualidade arquitetônica de um sistema e apenas cumprir os testes é obviamente tão ruim. Mas trapacear no local da construção de um arranha-céu ou uma ponte para economizar material e não seguir as plantas é tão ruim e acontece o tempo todo ...
fonte
Se você aceitar que quanto mais cedo os bugs forem encontrados, menor será o custo de corrigi-los, então isso fará com que o TDD valha a pena.
fonte
TDD não é realmente sobre testes. E certamente não é um substituto para bons testes. O que ele oferece é um design bem pensado, fácil para o consumidor consumir e fácil de manter e refatorar mais tarde. Essas coisas, por sua vez, levam a menos erros e a um design de software melhor e mais adaptável. O TDD também ajuda a refletir e documentar suas suposições, muitas vezes descobrindo que algumas delas estavam incorretas. Você as descobre muito cedo no processo.
E como um bom benefício colateral, você tem um grande conjunto de testes que pode executar para garantir que uma refatoração não altere o comportamento (entradas e saídas) do seu software.
fonte
Vou te dar uma resposta curta. Normalmente, o TDD é visto da maneira errada, assim como o teste de unidade. Eu nunca entendi o teste de unidade até recentemente, depois de assistir a um bom vídeo de conversa sobre tecnologia. Essencialmente, o TDD está apenas afirmando que você deseja que as seguintes coisas funcionem. Eles devem ser implementados. Em seguida, você projeta o restante do software da maneira que faria normalmente.
É como escrever casos de uso para uma biblioteca antes de projetá-la. Exceto que você pode alterar o caso de uso em uma biblioteca e talvez não o TDD (eu uso o TDD para o design da API). Você também é incentivado a adicionar mais testes e pensar em insumos / usos que o teste pode obter. Acho útil ao escrever bibliotecas ou APIs onde, se você alterar algo, deve saber que quebrou algo. Na maioria dos softwares do dia-a-dia, eu não me importo, pois por que eu preciso de um caso de teste para um usuário pressionando um botão ou se eu quero aceitar uma lista CSV ou uma lista com uma entrada por linha ... Isso realmente não importa. para alterá-lo assim eu não deveria / não posso usar TDD.
fonte
O software é orgânico, quando a engenharia estrutural é concreta.
Quando você constrói sua ponte, ela permanecerá uma ponte e é improvável que ela evolua para outra coisa dentro de um curto período de tempo. As melhorias serão feitas ao longo de meses e anos, mas não horas e dias, como no software.
Quando você testa isoladamente, normalmente existem dois tipos de estruturas que você pode usar. Estrutura restrita e irrestrita. Estruturas irrestritas (no .NET) permitem testar e substituir tudo, independentemente dos modificadores de acesso. Ou seja, você pode stub e zombar de componentes privados e protegidos.
A maioria dos projetos que eu vi usa estruturas restritas (RhinoMocks, NSubstitute, Moq). Ao testar com essas estruturas, é necessário projetar seu aplicativo de forma que você possa injetar e substituir dependências no tempo de execução. Isso implica que você deve ter um design fracamente acoplado. O design pouco acoplado (quando bem feito) implica uma melhor separação de preocupações, o que é uma coisa boa.
Para resumir, acredito que, pensando por trás disso, é que, se o seu design é testável, ele é fracamente acoplado e possui uma boa separação de preocupações.
Em uma nota lateral, vi aplicativos realmente testáveis, mas mal escritos da perspectiva do design orientado a objetos.
fonte
Não faz.
Esclarecimento: testes automatizados são melhores que nenhum teste. No entanto, eu pessoalmente acho que a maioria dos testes de unidade são desperdiçados porque geralmente são tautológicos (isto é, diz coisas óbvias do código real em teste) e não é fácil provar que eles são consistentes, não são redundantes e cobrem todos os casos de fronteira (onde geralmente ocorrem erros )
E o mais importante: um bom design de software não cai magicamente nos testes, pois é anunciado por muitos evangelistas ágeis / TDD. Qualquer pessoa que afirme o contrário, forneça links para pesquisas científicas revisadas por pares que comprovem isso, ou pelo menos faça referência a algum projeto de código aberto onde os benefícios do TDD possam ser potencialmente estudados pelo seu histórico de alterações de código.
fonte