Por que o TDD funciona? [fechadas]

92

O desenvolvimento orientado a testes (TDD) é grande hoje em dia. Costumo vê-lo recomendado como uma solução para uma ampla gama de problemas aqui no Programmers SE e outros locais. Eu me pergunto por que isso funciona.

Do ponto de vista da engenharia, isso me intriga por dois motivos:

  1. A abordagem "escrever teste + refatorar até passar" parece incrivelmente anti-engenharia. Se engenheiros civis usassem essa abordagem para a construção de pontes, ou projetistas de automóveis para seus carros, por exemplo, eles estariam reformando suas pontes ou carros a um custo muito alto, e o resultado seria uma bagunça remendada sem nenhuma arquitetura bem pensada. . A diretriz "refatorar até passar" é 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, em vez do usuário, define o requisito. Nesta situação, como podemos garantir boas "qualidades" nos resultados, ou seja, um resultado final que não é apenas correto, mas também extensível, robusto, fácil de usar, confiável, seguro, etc.? Isso é o que a arquitetura normalmente faz.
  2. O teste não garante que um sistema funcione; só pode mostrar que isso não acontece. 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 que um sistema que os falha. Cobertura de teste, qualidade de teste e outros fatores são cruciais aqui. Os falsos sentimentos de segurança que um resultado "todo verde" produz para muitas pessoas têm sido relatados nas indústrias civil e aeroespacial como extremamente perigosos, porque podem ser interpretados como "o sistema está bem", quando na verdade significa "o sistema é tão bom". como nossa estratégia de teste ". Muitas vezes, a estratégia de teste não é verificada. Ou quem testa os testes?

Em resumo, estou mais preocupado com o bit "dirigido" em TDD do que com o bit "test". O teste está perfeitamente bem; o que eu não entendo é dirigir o design fazendo isso.

Eu 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 eu expliquei acima não são relevantes (ou não são relevantes o suficiente) no caso de software. Obrigado.

    
por CesarGon 30.01.2011 / 14:17
fonte

19 respostas

66

Eu acho que há um equívoco aqui. No design de software, o design é muito próximo ao produto. Em engenharia civil, arquitetura, o design é desacoplado do produto real: há plantas que seguram o projeto, que depois são materializadas no produto acabado, e aqueles são separadas por enormes quantidades de tempo e esforço

.

O TDD está testando o design. Mas todo projeto de carro e projeto de construção também é testado. As técnicas de construção são primeiro calculadas, depois testadas em escala menor e depois testadas em escala maior, antes de serem colocadas em um prédio real. Quando eles inventaram H-vigas e a carga, por exemplo, descanse que isso foi tentado e tentado novamente antes dele construir a primeira ponte com ele.

Projetos de carros também são testados, projetando protótipos, e sim, certamente ajustando coisas que não são exatamente certas, até que ele corresponda às expectativas. Parte deste processo é mais lento, porque, como você disse, você não pode mexer muito com o produto. Mas todo redesenho de um carro baseia-se em experiências aprendidas com os antigos, e cada edifício tem cerca de mil anos de fundamentos sobre a importância do espaço, luz, isolamento, força, etc. Detalhes são alterados e melhorados, tanto nos edifícios e em redesenhar para os mais novos.

Além disso, as peças são testadas. Talvez não exatamente no mesmo estilo como software, mas peças mecânicas (rodas, ignitores, cabos) são normalmente medido e colocado sob estresse para conhecer os tamanhos estão corretos, não houve anormalidades são para ser visto, etc. Eles podem ser xrayed ou Laser- medidos, eles tocam tijolos para identificar os quebrados, eles podem ser realmente testados em alguma configuração ou outra, ou eles desenham uma representação limitada de um grande grupo para realmente colocá-lo em teste.

Essas são todas as coisas que você pode colocar em prática com o TDD.

E, de fato, o teste não é garantia. Os programas travam, 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ê não pode incluir tudo, ser capaz de cobrir - digamos - 99% das eventualidades é melhor do que cobrir apenas 50%. Não testar e, em seguida, descobrir que o aço não se adaptou bem e é frágil e quebra no primeiro tapa de um martelo quando você acabou de colocar sua estrutura principal é um simples desperdício de dinheiro. Que existem outras preocupações que podem ainda prejudicar o edifício não tornam menos estúpido permitir que uma falha facilmente evitável reduza seu design.

Quanto à prática do TDD, isso é uma questão de equilíbrio. O custo de fazer isso de uma maneira (por exemplo, não testando e depois pegando as peças mais tarde), versus o custo de fazer isso de outra maneira. É sempre um equilíbrio. Mas não pense que outros processos de design não possuem testes e TDD.

    
por 30.01.2011 / 15:02
fonte
25

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. Eu estou trabalhando em um grande aplicativo do silverlight onde os princípios do TDD são usados. O aplicativo tem centenas de testes, mas ainda não está estável. Várias partes do aplicativo não são testáveis devido às complexas interações do usuário. Testes resultantes com muitos truques e código difícil de entender.

Inicialmente, quando tentamos o TDD, tudo parece bom. Eu pude escrever muitos testes e zombar das partes que são difíceis para um teste de unidade. Depois de ter uma boa quantidade de código e uma mudança de interface é necessária, você está ferrado. Muitos testes precisam ser corrigidos e você irá reescrever mais testes do que a mudança real no código.

Peter Norvig Explica sua opinião sobre TDD no livro Coders At Work.

Seibel: What about the idea of using tests to drive design?

Norvig: I see tests more as a way of correcting errors rather than as a way of design. This extreme approach of saying, “Well, the first thing you do is write a test that says I get the right answer at the end,” and then you run it and see that it fails, and then you say, “What do I need next?”—that doesn’t seem like the right way to design something to me. It seems like only if it was so simple that the solution was preordained would that make sense. I think you have to think about it first. You have to say, “What are the pieces? How can I write tests for pieces until I know what some of them are?” And then, once you’ve done that, then it is good discipline to have tests for each of those pieces and to understand well how they interact with each other and the boundary cases and so on. Those should all have tests. But I don’t think you drive the whole design by saying, “This test has failed.”

    
por 31.01.2011 / 07:28
fonte
24

Test Driven Design funciona para mim pelos seguintes motivos:

É uma forma executável da especificação.

Isso significa que você pode ver os casos de teste:

  1. QUE o código sendo chamado preenche a especificação conforme os resultados esperados estão bem nos casos de teste. Inspecção visual (que espera que os casos de teste para passar) pode dizer imediatamente "oh, este teste verifica que chamando invoiceCompany dada esta situação, deve ter esse resultado".
  2. COMO o código deve ser chamado. As etapas reais necessárias para realizar os testes são especificadas diretamente, sem qualquer andaime externo (os bancos de dados são ridicularizados, etc.).

Você escreve a exibição do lado de fora primeiro.

O código freqüentemente é escrito de uma maneira em que você primeiro resolve o problema, e então você pensa em como o código que você acabou de escrever deve ser chamado. Isto freqüentemente dá uma interface desajeitada, porque é freqüentemente mais fácil "apenas adicionar uma bandeira", etc. Pensando no "precisamos fazer ISTO, para que os testcass fiquem parecidos com ISSO" na frente, vire isso. Isso dará uma melhor modularidade, já que o código será escrito de acordo com a interface de chamada, e não o contrário.

Isso geralmente resulta em códigos mais limpos, que exigem menos documentação explicativa.

Você termina mais rápido

Como você tem a especificação no formato executável, você está pronto quando a suíte de testes completa passar. Você pode adicionar mais testes à medida que esclarece as coisas em um nível mais detalhado, mas como um princípio básico, você tem um indicador muito claro e visível do progresso e quando está pronto.

Isso significa que você pode dizer quando o trabalho é necessário ou não (ajuda a passar em um teste) e você acaba precisando fazer menos.

Para aqueles que pensam sobre isso pode ser útil para eles, eu encorajo você a usar o TDD para sua próxima rotina de biblioteca. Lentamente, configure uma especificação executável e faça o código passar nos testes. Quando terminar, a especificação executável estará disponível para todos que precisarem ver como invocar 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 utilizaram a prática de TDD. Subjetivamente, as equipes experimentaram de 15 a 35 % de aumento no tempo de desenvolvimento inicial após a adoção do TDD. " ~ Resultados e Experiências de 4 Equipes Industriais

    
por 30.01.2011 / 17:57
fonte
19

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 ligar duas margens de um rio, é necessário primeiro um plano.

A abordagem do TDD se relaciona (principalmente) com o teste de unidade - pelo menos é assim que as pessoas tendem a pensar sobre isso - que está criando os bits mais baixos de código de software. Quando todos os recursos e comportamentos já foram definidos e realmente sabemos o que queremos alcançar.

Na engenharia estrutural, parece um pouco assim:

'We have these two pieces of metal connected together, and the connection needs to sustain shear forces in the order of x. Let's test which connection method is the best one to do this'

Para testar se o software funciona como um todo, criamos outros tipos de testes, como testes de usabilidade, testes de integração e testes de aceitação. Eles também devem ser definidos antes do trabalho real de escrever o código, e são executados depois que os testes de unidade ficarem verdes.

Veja o V-Model: link

Vamos ver como isso funcionaria para uma ponte:

  1. Um governo local diz a uma empresa de construção de pontes: "Precisamos de uma ponte para conectar esses dois pontos. A ponte precisa ser capaz de permitir uma quantidade de tráfego por hora e estar pronta para 21 de dezembro de 2012" - esta é uma definição de teste de aceitação.A empresa não receberá quantia total (ou qualquer) de dinheiro, se não puder passar no teste.

  2. 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 essas metas, a ponte não será construída a tempo. No entanto - há algum nível de flexibilidade aqui. Se uma das equipes tiver alguns problemas, a empresa pode compensar isso alterando os requisitos, alterando os subcontratados, contratando mais pessoas, etc., para que todo o projeto ainda atenda à meta estabelecida no ponto 1.

  3. Dentro de uma equipe responsável por projetar componentes de ponte específicos, parece que no exemplo que 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ê supõe que ela funciona 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 de antemão.

por 30.01.2011 / 14:24
fonte
18

Na minha opinião, o TDD funciona porque

  • Ele força você a definir o que deseja que a unidade faça antes de decidir sobre a implementação em um nível de precisão geralmente não coberto por qualquer documento de requisitos ou especificações
  • Torna o seu código inerentemente reutilizável, porque você precisa usá-lo em testes e cenários de produção
  • Ele incentiva você a escrever código em um operador menor para testar fragmentos que tendem a levar a melhores designs

Especificamente sobre os pontos que você levanta

  • O código é mais maleável que o tijolo ou o aço, por isso é mais barato modificá-lo. É mais barato ainda se você tiver testes para garantir que o comportamento não seja alterado
  • TDD não é uma desculpa para não fazer design - uma arquitetura de alto nível ainda é aconselhável, mas não com muitos detalhes. O Big Up Front Design é desencorajado, mas é incentivado apenas o design suficiente
  • O TDD não garante que um sistema funcione, mas evita muitos pequenos erros que, de outra forma, seriam perdidos. Além disso, como geralmente incentiva um código melhorado, muitas vezes é mais fácil de entender e, portanto, é menos provável que tenha bugs
por 30.01.2011 / 16:19
fonte
16

TL; DR

A programação ainda é uma atividade de design, não é construção. Escrever testes unitários após o fato só confirma que o código faz o que ele faz, não que ele faça algo útil. As falhas de teste são o valor real porque permitem que você detecte erros precocemente.

O código é design

No Capítulo 7 do PPP "Uncle Bob" fala sobre esse assunto diretamente. Muito no início do capítulo, ele faz referência a um artigo excelente de Jack Reeves, no qual ele propõe que o código seja design (o link vai para uma página coletando todos os três artigos dele sobre o tópico).

O que é interessante sobre este argumento é que ele aponta, ao contrário de outras disciplinas de engenharia onde a construção é uma atividade muito cara, a construção de software é relativamente livre (compilar em seu IDE e você tem seu software construído). Se você visualizar o código de gravação como uma atividade de design em vez de uma atividade de construção, o ciclo do refator vermelho-verde é basicamente um exercício no design. Seu design evolui à medida que você escreve testes, o código para satisfazê-los e refatora para integrar o novo código no sistema existente.

TDD como especificação

Os testes de unidade que você escreve para o TDD são uma tradução direta da especificação como você os entende. Ao escrever um código que satisfaça minimamente sua especificação (faz seus testes ficarem verdes), todo o código que você escreveu está lá para uma finalidade específica. O cumprimento ou não dessa finalidade é validado por um teste repetível.

Escrever testes na funcionalidade

Um erro comum no teste de unidade acontece quando você escreve os testes depois do código, você acaba testando que o código faz o que ele faz. Em outras palavras, você verá testes como este

public class PersonTest:Test
{
   [Test]
   TestNameProperty()
   {
      var person=new Person();
      person.Name="John Doe";
      Assert.AreEqual("John Doe", person.Name);
   }
}

Embora eu ache que esse código pode ser útil (certifique-se de que alguém não tenha feito algo obsceno com uma propriedade simples). Não serve para validar uma especificação. E como você disse, escrever esses tipos de testes leva você até certo ponto.

Enquanto o verde é bom, o valor está no vermelho Eu tive meu primeiro verdadeiro momento "aha" em TDD quando recebi uma falha inesperada no teste. Eu tinha um conjunto de testes que eu tinha para um framework que eu estava construindo. Adicionando um novo recurso, eu escrevi um teste para isso. Em seguida, escreveu o código para fazer o teste passar. Compile, teste ... ficou verde no novo teste. Mas também ficou vermelho em outro teste que eu não esperava ficar vermelho.

Olhando para o fracasso, eu suspiro aliviado porque eu duvido que eu teria pego esse bug por um bom tempo se eu não tivesse feito o teste no lugar. E foi um erro muito desagradável de ter. Felizmente, fiz o teste e ele me disse exatamente o que eu precisava fazer para consertar o bug. Sem o teste, eu teria mantido a construção do meu sistema (com o bug infectando outros módulos que dependiam desse código) e, quando o bug fosse descoberto, teria sido uma tarefa importante corrigi-lo corretamente.

O verdadeiro benefício do TDD é que 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 constrangedor. Sem isso é uma tragédia. No mesmo sentido, TDD evita que você transforme erros tontos em projetos que matam desastres.

    
por 31.01.2011 / 18:44
fonte
11

Você não encontrará ninguém que defenda o Desenvolvimento Dirigido por Testes, ou mesmo o Design Testado com Droga (eles são diferentes), que diz que os testes comprovam os aplicativos. Então vamos chamar isso de palhaço e acabar.

Você não encontrará ninguém que não goste ou não fique impressionado com o TDD que diz que os testes são um desperdício 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 nada diferente em relação à realização de testes no software. Ambos estão fazendo testes. Ambos dependem do teste para encontrar tantos bugs quanto possível, e ambos usam testes para verificar se um programa de software está funcionando tão bem quanto pode ser descoberto no momento. Ninguém com metade de uma dica vende software sem testes e ninguém com a menor idéia espera que o teste vá renderizar o código que eles vendem completamente sem bug.

Então, a diferença entre TDD e não-TDD não é que testes estão sendo feitos. A diferença está em quando os testes são escritos. Em 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 tenho visto em relação a este último é que o teste tende a direcionar o software que está sendo escrito mais do que o resultado desejado ou especificação. Mesmo com a equipe de testes sendo separada da equipe de desenvolvimento, a equipe de teste tende a olhar para o software, brincar com ele e escrever testes que o direcionam.

Uma coisa que tem sido notada várias vezes por aqueles que estudam o sucesso do projeto, é a frequência com que um cliente define o que quer, o desenvolvimento das pessoas que correm e escrevem algo e quando voltam ao cliente dizendo "feito" acaba por ser totalmente e completamente NÃO o que o cliente pediu. "Mas passa todos os testes ..."

O objetivo do TDD é quebrar este "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 esses testes.

O TDD é a 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 feedback dos clientes e com mais frequência.

Na minha experiência, porém, TDD é uma coisa muito difícil de implementar com sucesso. É difícil obter testes escritos antes de existir um produto, porque muitos testes automatizados exigem ter algo com o que fazer para que o software de automação funcione corretamente. Também é difícil conseguir que desenvolvedores que não estão acostumados a testes de unidade façam isso. Uma e outra vez eu disse às pessoas da minha equipe para escrever os testes PRIMEIRO. Eu nunca consegui fazer isso. No final, restrições de tempo e política destruíram todos os esforços para que nem sequer fizéssemos mais testes unitários. Isto, obviamente, conduz inevitavelmente ao desenho ser acidentalmente e severamente acoplado, de modo que, mesmo se quiséssemos, seria agora dispendiosamente caro implementar. Evitar isso é o que o TDD fornece aos desenvolvedores.

    
por 30.01.2011 / 21:50
fonte
9

Design primeiro

TDD é não uma desculpa para ignorar o design. Eu vi muitos pularem no movimento "ágil" porque eles poderiam começar a codificar imediatamente. A verdadeira agilidade fará com que você codifique estatisticamente muito mais rápido 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 projeto, simplesmente significa que é possível usar testes muito cedo na fase de projeto, muito antes de estar completo. Fazer esses testes influenciará strongmente o seu projeto desafiando as áreas cinzas e colocando-as contra o mundo real muito antes de o produto ser concluído. forçando você a voltar a projetar e ajustá-lo para levar isso em conta.

Teste e desenho ... um e o mesmo

Na minha opinião, o TDD simplesmente faz com que o teste seja uma parte integral do design, em vez de algo feito no final para validá-lo. À medida que você começa a usar o TDD cada vez mais, fica com a mentalidade de como destruir / quebrar seu sistema conforme o projeto. Pessoalmente, nem sempre faço meus testes primeiro. Claro que faço os testes óbvios (unitários) em uma interface, mas os ganhos reais vêm dos testes de integração e especificação que eu crio quando penso em uma maneira nova e criativa como esse design pode ser quebrado. Assim que penso em um caminho, codifico um teste para ele e vejo o que acontece. Às vezes eu posso viver com a consequência, neste caso eu 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 acionamento aqui significa simplesmente que seus testes influenciam tão strongmente o seu projeto que se pode sentir que eles estão realmente dirigindo. No entanto, para isso, e aqui eu entendo suas preocupações, é um pouco assustador ... quem dirige o show?

VOCÊ está dirigindo, não os testes. Os testes estão aí, de modo que, à medida que você avança, você obtém um bom nível de confiança no que você criou, permitindo que você construa mais, sabendo que ele se baseia em fundamentos sólidos.

sólido, desde que os testes sejam sólidos

Exatamente , daí o direcionado no TDD. Não é tanto que os testes estejam guiando a coisa toda, mas eles terão uma influência tão profunda sobre como você faz as coisas, sobre como projetar e pensar em seu sistema que delegará uma grande parte de seu processo de raciocínio a testes e em retorno. eles terão uma influência profunda no seu design.

sim, mas se eu fizer isso com a minha ponte ....

pare aí ... a engenharia de software é MUITO diferente de qualquer outra prática de engenharia existente. Na verdade, a engenharia de software tem muito mais em comum com a literatura. Pode-se pegar um livro acabado, extrair 4 capítulos dele e escrever dois novos capítulos para substituí-los de volta no livro e você ainda terá um bom livro. Com bons testes e softwares, você pode copiar qualquer parte do seu sistema e substituí-lo por outro, e o custo de fazer isso não é muito maior do que foi criado em primeiro lugar. Na verdade, se você fizesse seus testes e permitisse que eles influenciassem seu design o bastante, seria muito mais barato do que criá-lo, já que você terá um certo nível de confiança de que esse substituto não quebrará o que os testes estão cobrindo.

Se é tão bom, como é que nem sempre funciona?

Porque o teste requer uma mentalidade MUITO diferente do que a construção faz. Nem todo mundo é capaz de voltar e voltar, na verdade algumas pessoas não serão capazes de construir testes adequados simplesmente porque não podem definir sua mente para destruir sua criação. Isso resultará em projetos com poucos testes ou testes suficientes para atingir as métricas de destino (a cobertura de código vem à mente). Eles vão testes de caminho feliz e testes de exceção, mas vão esquecer os casos de canto e as condições de contorno.

Outros apenas confiam em testes que abandonam o design parcial ou totalmente. Cada membro fazendo a coisa, em seguida, integrando uns com os outros. O design é, antes de tudo, uma ferramenta de comunicação, estacas que colocamos no chão para dizer que é onde estarei, esboços que dizem que é onde as portas e janelas estarão. Sem isso, o seu software está condenado, independentemente de quantos testes você colocou na coisa. A integração e as mesclagens sempre serão dolorosas e não terão testes nos níveis mais altos de abstrações.

Tor essas equipes TDD pode não ser o caminho a percorrer.

    
por 21.10.2011 / 05:17
fonte
7

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 uma coisa pequena, 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 familiarizar com o melhor código de usuário suportado pelos testes.

    
por 30.01.2011 / 15:04
fonte
5

Eu tenho pensado muito sobre isso, mesmo que eu não pratique TDD tanto assim. Parece haver uma correlação positiva (strong?) Entre a qualidade do código e após o TDD.

1) Minha primeira opinião é que, isto é (principalmente) não devido ao TDD adicionar "melhor qualidade" ao código (como tal), é mais como o TDD ajuda a eliminar partes piores e hábitos, aumentando indiretamente a qualidade.

Eu até defendo que não é o teste em si - é o processo de escrever esses testes. É difícil escrever testes para um código ruim e vice-versa. E mantendo isso na parte de trás da cabeça durante a programação, elimina muito código ruim.

2) Outro ponto de vista (isto está ficando filosófico) está seguindo os hábitos mentais do mestre. Você não aprende a se tornar um mestre seguindo seus "hábitos externos" (como uma boa barba é boa), você deve aprender seus modos internos de pensar, e isso é difícil. E de alguma forma, os programadores (novatos) seguem o TDD, alinham seus modos de pensar mais próximos aos do mestre.

    
por 30.01.2011 / 16:04
fonte
3

The "write test + refactor till pass" approach looks incredibly anti-engineering.

Você parece ter um equívoco sobre refatoração e TDD.

Code refactoring is the process of changing a computer program's source code without modifying its external functional behavior in order to improve some of the nonfunctional attributes of the software.

Assim, você não pode refatorar o código até que ele passe.

E o TDD, especificamente o teste unitário (que eu considero o melhoramento do núcleo, já que outros testes parecem bastante plausíveis para mim), não é sobre redesenhar um componente até que ele funcione. Trata-se de projetar um componente e trabalhar na implementação até que o componente funcione conforme planejado.

Além disso, é importante compreender realmente que o teste unit é sobre o teste de unidades . 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 usa (os diferentes materiais) e pode esperar que funcionem. Estas são duas coisas que muitas vezes não se aplicam a engenheiros de software, e é muito pró-engenharia testar as unidades antes de usá-las, porque isso significa usar componentes testados e de alta qualidade. Se um engenheiro civil teve a ideia de usar um novo tecido de fibra para fazer um telhado para cobrir um estádio, você esperaria que ele o testasse como uma unidade, ou seja, definisse as especificações necessárias (por exemplo, peso, permeabilidade, estabilidade, etc.) e depois testasse e refinasse até encontrá-las.

É por isso que o TDD funciona. Porque se você criar um software de unidades testadas, as chances são muito melhores de funcionar, quando você as conecta e, se não, você pode esperar que o problema esteja no seu código de cola, supondo que seus testes tenham uma boa cobertura.

edit:
Refatoração significa: não alteração na funcionalidade. Um ponto para escrever um teste unitário é garantir que a refatoração não quebre o código. Então, 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, em que a granularidade é exatamente definida.

O TDD incentiva uma boa arquitetura. Ela exige que você defina e implemente especificações para todas as suas unidades, forçando-o a projetá-las antes da implementação, o que é completamente o contrário do que você parece pensar. O TDD determina a criação de unidades, que podem ser testadas individualmente e, portanto, completamente desacopladas. TDD não significa que eu faça um teste de software com código de espaguete e mexa a massa até ela passar.

Em contraste com a engenharia civil, na engenharia de software, um projeto geralmente evolui constantemente. Na engenharia civil, você tem a obrigação de construir uma ponte na posição A, que possa transportar x toneladas e seja 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), ele quer uma ponte dupla, e quer conectá-la à rodovia mais próxima, e que gostaria que ela fosse uma ponte de elevação, porque sua empresa recentemente começou a usar navios à vela.
Engenheiros de software são encarregados de alterar projetos. Não porque seus projetos são falhos, mas porque esse é o modus operandi. Se o software for bem projetado, ele pode ser redesenhado em alto nível, sem ter que reescrever todos os componentes de baixo nível.

O TDD trata da criação de software com componentes testados individualmente e altamente desacoplados. Bem executado, ajudará você a responder às mudanças nos requisitos de maneira mais rápida e segura do que sem.

O TDD adiciona requisitos ao processo de desenvolvimento, mas não proíbe quaisquer outros métodos de garantia de qualidade. Concedido, o TDD não oferece a mesma segurança que a verificação formal, mas, novamente, a verificação formal é extremamente custosa e impossível de ser usada no nível do sistema. E ainda, se você quisesse, você poderia combinar os dois.

O TDD também engloba outros testes que não testes unitários, 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, são bastante plausíveis. Enquanto eu absolutamente vejo sua necessidade, eu realmente não os valorizo 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 arquitetura excelente? Bem, se você planeja fazer paredes retas, tijolos retos são de ajuda. E sim, concedido, se você der essa ferramenta para um idiota, ele provavelmente vai bater no pé dele eventualmente, mas isso não é culpa do formão, tanto quanto não é uma falha do TDD que dá falsa segurança aos novatos, quem não escreve bons testes.
Então, na linha de fundo, pode-se dizer que o TDD funciona muito melhor do que nenhum TDD.

    
por 31.01.2011 / 13:59
fonte
2

Não gosto do seu dizer "o teste, em vez do usuário, define o requisito". Eu acho que você está considerando apenas testes unitários em 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 têm com o software / site / o que quer que seja. Estes vêm diretamente dos usuários, e bibliotecas como o cucumber (http://cukes.info) podem até permitir que seus usuários escrevam os próprios testes, em linguagem natural.

O TDD também incentiva a flexibilidade no código - se você gasta para sempre projetar a arquitetura de algo, será incrivelmente difícil fazer essas alterações mais tarde, se necessário. Comece escrevendo alguns testes e, em seguida, 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, um único software pode sofrer grandes mudanças ao longo de sua vida útil, e refactoring complexo sem ter os testes escritos em primeiro lugar é apenas perguntando por problemas.

    
por 30.01.2011 / 14:36
fonte
2

Acho que você está se aproximando do primeiro ponto do ângulo errado.

Do ponto de vista teórico, estamos provando que algo funciona verificando 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 da abordagem bit-wise: se não quebrar, funciona.

Na prática, isso simplesmente se traduz em: agora podemos passar para a próxima coisa (depois de termos aplicado com sucesso o TDD para satisfazer todos os predicados). Se você abordar o TDD a partir dessa perspectiva, então não se trata de "escrever testes + refatorar até passar", é mais sobre ter completado isso, agora estou totalmente focado no próximo recurso como a coisa mais importante .

Pense 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 é boa, satisfizemos segurança primeiro . Agora podemos nos concentrar em outras questões que se tornam imediatamente importantes, como banheiros, barracas de comida, assentos, etc ... tornando a experiência do público mais prazerosa. Isso é uma simplificação excessiva, já que há muito mais no TDD, mas o ponto crucial é que você não faz a melhor experiência de usuário possível se estiver focando em recursos novos e empolgantes e mantendo a integridade ao mesmo tempo. Você obtém metade do caminho em ambos os casos. Quero dizer, como você pode saber exatamente em quantos banheiros e onde você deve colocar para 150000 pessoas? Eu raramente vi estádios desabarem durante minha vida, mas tive que esperar na fila durante o intervalo em muitas ocasiões. Isso diz que o problema do lavatório é discutivelmente mais complexo e, se os engenheiros puderem gastar menos tempo com segurança, eles poderão finalmente resolver a questão do banheiro.

Seu segundo ponto é irrelevante, porque já concordamos que os absolutos são um tolos esforçar-se e porque Hank Moody diz que eles não existem (mas não consigo encontrar uma referência para isso).

    
por 31.01.2011 / 00:56
fonte
1

TDD em engenharia de software é uma boa prática, da mesma forma que o tratamento de erros em aplicativos é uma boa prática, bem como registros e diagnósticos (embora seja parte do tratamento de erros).

O TDD não deve ser usado como uma ferramenta para reduzir o desenvolvimento de software no teste & codificação de erro. Mas ainda assim, a maioria dos programadores observam os logs de tempo de execução, observam exceções no depurador ou usam outros sinais de falha / sucesso durante sua fase de desenvolvimento, que consiste em codificar / compilar / executar o aplicativo - o dia todo.

O TDD é apenas uma maneira de formalizar e automatizar essas etapas para torná-lo mais produtivo como desenvolvedor.

1) Você não pode comparar engenharia de software para construir pontes, a flexibilidade na construção de pontes não está muito próxima da de projetar um programa de software. Construir a ponte é como escrever o mesmo programa repetidas vezes em uma máquina com perdas. Bridges não podem ser duplicados e reutilizados como software. Cada ponte é única e precisa ser fabricada. O mesmo vale para carros e outros projetos.

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 é fácil, em teoria, reproduzir a falha. Quando um programa de computador falha, pode ser uma cadeia complexa de eventos que colocou o sistema em um estado defeituoso e pode ser muito difícil determinar onde está o erro. O TDD e o teste unitário tornam mais fácil testar a robustez dos componentes de software, bibliotecas e algoritmos.

2) Usar testes de unidade fracos e casos de teste superficiais que não estressem o sistema para criar um falso senso de confiança é apenas uma má prática. Ignorando a qualidade arquitetural de um sistema e apenas cumprindo os testes são, obviamente, tão ruins. Mas trapacear no local da construção para um arranha-céu ou uma ponte para economizar material e não seguir as plantas é tão ruim e acontece o tempo todo ...

    
por 30.01.2011 / 16:47
fonte
1

Se você aceitar que os erros mais cedo são encontrados, menos o custo de consertá-los, então isso por si só faz com que o TDD valha a pena.

    
por 30.01.2011 / 23:38
fonte
0

O TDD não é realmente sobre testes. E certamente não é um substituto para um bom teste. O que ele oferece é um design bem pensado, fácil para o consumidor consumir e manter e refatorar mais tarde. Essas coisas, por sua vez, levam a menos bugs e a um design de software melhor e mais adaptável. O TDD também ajuda você a analisar e documentar suas suposições, geralmente descobrindo que algumas delas estavam incorretas. Você descobre isso logo no início do processo.

E como um bom benefício secundário, você tem um grande conjunto de testes que pode ser executado para garantir que uma refatoração não altere o comportamento (entradas e saídas) do seu software.

    
por 30.01.2011 / 17:25
fonte
0

Eu vou te dar uma resposta curta. Normalmente, o TDD é visto da maneira errada, assim como o teste de unidade. Eu nunca entendi o teste unitário até recentemente, depois de assistir a um vídeo de boa tecnologia. Essencialmente, o TDD está apenas dizendo que você quer que as seguintes coisas funcionem. Eles devem ser implementados. Então você projeta o resto do software da maneira que normalmente faria.

É como escrever casos de uso para uma biblioteca antes de projetar a biblioteca. Exceto que você pode alterar o caso de uso em uma biblioteca e talvez não seja para o TDD (eu uso o TDD para o design da API). Você também é incentivado a adicionar mais testes e pensar em insumos / utilizações que o teste pode receber. Acho que é útil ao escrever bibliotecas ou APIs onde, se você mudar algo, você deve saber que você quebrou alguma coisa. Na maioria dos softwares do dia a dia eu não me incomodo, porque eu preciso de um caso de teste para um usuário pressionando um botão ou se eu quiser aceitar uma lista CSV ou uma lista com uma entrada por linha ... Isso realmente não importa para mudá-lo, assim eu não deveria / não posso usar TDD.

    
por 21.10.2011 / 10:13
fonte
0

O software é orgânico, quando a engenharia estrutural é concreta.

Quando você constrói sua ponte, ela continuará sendo uma ponte e é improvável que ela evolua para outra coisa dentro de um curto período de tempo. Melhorias serão feitas ao longo de meses e anos, mas não horas e dias como em software.

Quando você testa isoladamente, normalmente há dois tipos de frameworks que você pode usar. Estrutura restrita e irrestrita. Estruturas irrestritas (no .NET) permitem que você teste e substitua tudo, independentemente dos modificadores de acesso. Ou seja você pode esboçar e simular componentes particulares e protegidos.

A maioria dos projetos que vi usam estruturas restritas (RhinoMocks, NSubstitute, Moq). Quando você testa com essas estruturas, você precisa projetar seu aplicativo de forma que possa injetar e substituir dependências em tempo de execução. Isto implica que você deve ter um design fracamente acoplado. O design de acoplamento fraco (quando feito corretamente) implica uma separação melhor das preocupações, o que é uma coisa boa.

Para resumir, acredito que o pensamento por trás disso é que, se o seu design é testável, ele é fracamente acoplado e tem uma boa separação de interesses.

Em uma nota lateral, eu vi aplicativos que eram realmente testáveis, mas mal escritos de uma perspectiva de projeto orientada a objetos.

    
por 06.05.2014 / 11:30
fonte
0

Why does TDD work?

Isso não acontece.

Esclarecimento: testes automatizados são melhores que nenhum teste. No entanto, eu pessoalmente acho que a maioria dos testes unitários são resíduos porque eles geralmente são tautológicos (isto é, dizem coisas óbvias do código real em teste) e não pode ser facilmente provado que eles são consistentes, não redundantes e cobrem todos os casos de fronteira ).

E o mais importante: o bom design de software não cai magicamente nos testes, como é anunciado por muitos evangelistas ágeis / TDD. Todos os que reivindicam o contrário, por favor forneçam links para pesquisas científicas revisadas por pares que provem isso, ou pelo menos façam referência a algum projeto de código aberto onde os benefícios do TDD possam ser potencialmente estudados pelo histórico de mudanças de código.

    
por 10.11.2014 / 21:30
fonte

Tags