Por que o TDD funciona? [fechadas]

92

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:

  1. 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.
  2. 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.

CesarGon
fonte
53
Pontes, carros e outros projetos físicos não são tão maleáveis ​​quanto o software. Essa é uma distinção importante e significa que as comparações entre software e engenharia real nem sempre são relevantes. O que funciona para pontes pode não funcionar para software e vice-versa.
Lars Wirzenius
9
Eu concordo um pouco com suas dúvidas. Por exemplo, confesso que tenho a impressão de que ter um conjunto de testes pode ter como efeito colateral uma atenção "suavizada" de alguma forma ao escrever código. É claro que os testes são uma coisa boa (obrigatória se você quiser ter a possibilidade de refatorar), mas apenas se eles complementarem a atenção aos detalhes, casos de fronteira, eficiência ou extensibilidade e não se substituí-los.
6502
2
@ 6502: Por todos os meios! O TDD não é uma bala de prata e não resolverá todos os problemas que surgem durante o desenvolvimento do software. No entanto, é um método útil para organizar o fluxo de trabalho. Você pode, por exemplo, impor uma exigência de que todos os casos de fronteira sejam cobertos por testes. Você ainda precisa saber quais são esses casos de borda, mas agora você também tem uma ferramenta para verificar se o seu código lida com eles corretamente.
Mchl
2
@ CesarGon, você também pode ser interessante nessa pergunta que fiz há algum tempo ... Não exatamente no TDD, mas relacionado ... Algumas respostas muito esclarecedoras lá.
AviD 30/01
6
É incrível o fato de um analógico de engenharia civil / desenvolvimento de software não se sustentar. Na mesma linha, sempre notei que não posso cozinhar panquecas da mesma maneira que corto a grama.

Respostas:

66

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.

Inca
fonte
7
+1 por falar sobre onde os testes ocorrem na fabricação. Ótimo ponto.
Adam Lear
11
Você diz que "as peças são testadas". Claro, mas não testado. Uma peça de aeronave não é projetada de maneira orientada a teste, mas de maneira arquitetônica e com grande design inicial. As semelhanças com TDD são inexistentes aqui.
CesarGon
3
Acrescentando a isso: TDD é, na minha opinião, principalmente sobre maneiras de garantir que você verifique as partes em vez de um grande 'tudo ou nada' no final. Mas o adágio do TDD, 'construa um teste primeiro', não deve ser 'faça um teste antes de pensar no que deseja realizar'. Porque pensar em um teste faz parte do design. A especificação do que você deseja que essa peça exata faça é o design. Antes de começar a digitar, você já fez um design. (Dessa forma, acho que o termo "design orientado a testes" implica enganosamente em um caminho de caminho, onde é realmente um ciclo de feedback).
Inca
2
+1: O software é puramente design. A analogia da ponte na questão está completamente errada. O TDD aplica-se totalmente a testes de unidade externos. O Design Orientado a Testes se aplica a todas as camadas do design.
precisa saber é o seguinte
3
@ CesarGon: Não, o TDD está conduzindo o DESENVOLVIMENTO testando. Isso é diferente de conduzir o design. O design determina como você usaria o sistema e, portanto, quais testes você precisaria implementar para replicar esse comportamento. A implementação desses testes geralmente ajuda a refinar o design.
deworde
26

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.

Seibel: E a ideia de usar testes para conduzir o design?

Norvig: Eu vejo os testes mais como uma maneira de corrigir erros, e não como uma maneira de projetar. Essa abordagem extrema de dizer: "Bem, a primeira coisa que você faz é escrever um teste que diga que eu recebo a resposta certa no final" e, em seguida, execute-o e veja que ele falha e depois diga: "O que eu faço?" precisa em seguida? ”- isso não parece o caminho certo para projetar algo para mim. Parece que apenas se fosse tão simples que a solução fosse predeterminada, isso faria sentido. Eu acho que você tem que pensar sobre isso primeiro. Você tem que dizer: “Quais são as peças? Como posso escrever testes para peças até saber quais são algumas delas? ”E então, depois de fazer isso, é uma boa disciplina fazer testes para cada uma dessas peças e entender bem como elas interagem umas com as outras. e os casos de fronteira e assim por diante. Todos devem ter testes. Mas acho que você não conduz todo o projeto dizendo: "Este teste falhou".

Navaneeth KN
fonte
7
Agora, se você contar esses fatos para as pessoas e consultores da TDD, a resposta que você obtém seria:well, you haven't done TDD right!
Navaneeth KN
10
E eles estariam certos. Estamos executando o BDD / TDD em um sistema de volume muito alto e está funcionando bem. Os testes existem para lhe dizer que você quebrou o comportamento esperado. Se você vai mudar isso mais tarde "quebrando" os testes, está de fato fazendo errado. Os testes devem ser alterados primeiro para solidificar o novo comportamento do sistema e, em seguida, você o altera. E sim, se você estiver fazendo o certo, você escreve seus testes começando com "o que essa coisa precisa fazer" e o processo de escrever o teste ajuda a pensar "o que a TI precisa para fazer seu trabalho". Ah, e há consultores foram já usou ...
Andy
4
Fazer muitos testes não o isenta de criar um design adequado. Um design altamente acoplado, independentemente de quantos testes são construídos em torno dele, é e sempre será frágil. a incorporação de testes nesse design pode muito bem tornar a coisa ainda pior.
Newtopian 21/10
3
Não se trata de fazer errado ou de ser um design altamente acoplado. O fato é que as interfaces mudam. Isso significa que todos os testes que usam essa interface devem ser alterados. Em grandes sistemas, manter os testes sincronizados com as alterações necessárias pode começar a sobrecarregar a implementação. Isso se torna um problema ainda maior se você estiver desenvolvendo agilmente, pois as chances de alterações na interface são muito mais prováveis. É engraçado como, quando as metodologias não funcionam, os proponentes da metodologia insistem que você está fazendo errado. É mais provável que a metodologia não seja adequada para todos os domínios problemáticos.
Dunk
2
Na minha experiência, o TDD funciona para pequenas aplicações ou módulos. Quando tenho que trabalhar em algo complexo, o TDD me deixa mais lento porque me obriga a escrever uma especificação detalhada (executável) antes de ter uma ideia geral clara: então me perco nos detalhes muito cedo, e muitas vezes preciso jogue fora um monte de testes se descobrir que não preciso de determinadas classes (ainda estou brincando com o design). Nesses casos, prefiro obter um design geral razoável primeiro e depois detalhar os detalhes da implementação (possivelmente usando TDD).
Giorgio
25

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:

  1. QUE o código que está sendo chamado preenche totalmente a especificação, pois os resultados esperados estão lá nos casos de teste. A inspeção visual (que espera que os casos de teste passem) pode dizer imediatamente "ah, esse teste verifica se a empresa de fatura de chamada, dada essa 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 andaimes externos (bancos de dados são zombados etc.).

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

Dave Jarvis
fonte
5
Eu acrescentaria que você realmente tem uma orientação razoável e clara sobre quando terminar. Sem um procedimento claro para verificar objetivamente se você concluiu a tarefa em mãos, é difícil saber. Minha própria experiência inclui muitas horas e dias desperdiçados em "negociação" se uma tarefa foi concluída e um movimento contínuo e constante da linha. Isso afeta todos os níveis de gerenciamento de projetos, incluindo o agendamento, pois como você pode agendar uma tarefa dessas? Alvos mais claros com retorno mais rápido aumentam a taxa de transferência E a comunicação.
Edward Strange
Essa deve ser a resposta aceita.
Niing
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 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:

'Temos esses dois pedaços de metal conectados juntos, e a conexão precisa sustentar forças de cisalhamento na ordem de x. Vamos testar qual método de conexão é o melhor para fazer 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:

  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 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.

  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 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.

  3. 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.

Mchl
fonte
Se eu entendi direito, você está dizendo que o TDD está OK, desde que (a) seja usado apenas para testes de unidade e (b) seja acompanhado por outras abordagens de teste também. Se for esse o caso, ele pode endereçar o ponto número 2 no OP. Como você abordaria o ponto número 1?
CesarGon
@CesarGon: TDD também funciona muito bem para testes de integração.
sevenseacat
O ponto 1 resume-se ao ato de que, antes que o projeto final de um carro ou uma ponte seja aceito, ele passa por muitas reiterações durante as quais todos os seus detalhes são revisados ​​e testados em relação aos requisitos impostos pelo 'plano de escopo amplo'. É feito principalmente no papel (ou na memória do computador), porque é mais barato nesse caso, mas observe que muitas vezes existem protótipos físicos sendo construídos de toda a construção (não no caso da ponte, talvez), bem como de seus componentes.
Mchl
@Karpie: E para testes de aceitação também! Você deve saber de antemão o que é necessário para que seu trabalho seja aceito pelo cliente.
Mchl
1
OK então. Praticamente a primeira equipe a iniciar o trabalho é uma equipe de arquitetos que é instruída a projetar uma ponte capaz de atender aos critérios dos clientes, além de ser barata e possivelmente ter uma boa aparência e não cair na primeira rajada de vento. A equipe pode propor alguns projetos aproximados, mais ou menos, que atendam a esses critérios, depois selecione um e trabalhe com mais detalhes, repita, repita, repita até que o projeto esteja pronto (isto é, atende aos critérios fornecidos e é suficientemente detalhado para que outras etapas do projeto podem começar)
Mchl 30/01
18

Na minha opinião, o TDD funciona porque

  • Isso obriga a definir o que você 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 nenhuma especificação ou requisito.
  • Torna seu código inerentemente reutilizável, porque você precisa usá-lo nos cenários de teste e produção
  • Ele incentiva você a escrever código em um ansioso menor para testar pedaços que tendem a levar a melhores designs

Especificamente nos pontos que você levanta

  • O código é mais maleável que o tijolo ou o aço, por isso é mais barato modificá-lo. Ainda é mais barato se você tiver testes para garantir que o comportamento não seja alterado
  • O TDD não é uma desculpa para não fazer design - uma arquitetura de alto nível ainda é geralmente recomendada, mas não com muitos detalhes. O projeto Big Up Front é desencorajado, mas é recomendável fazer o design suficiente
  • O TDD não pode garantir que um sistema funcione, mas evita que ocorram muitos pequenos erros que, de outra forma, seriam perdidos. Também porque geralmente incentiva um código fatorado melhor, geralmente é mais fácil entender, portanto, é menos provável que seja um bug
Gavin Clarke
fonte
3
Você também deve adicionar que, à medida que os defeitos são descobertos, você pode garantir que eles não serão repetidos, pois você adicionará outro teste.
Andy
16

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

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 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.

Michael Brown
fonte
4
O valor de testes em vermelho detectando bugs é um atributo do Teste de Unidade em geral, não do TDD especificamente.
Robert Harvey
2
Você está certo nesse ponto. Mas a probabilidade de eu ter esse bug específico coberto com testes de unidade post-hoc é menor.
Michael Brown
1
Você pode apoiar essa afirmação com alguma evidência, dados ou análise sólida?
CesarGon
1
@CesarGon este estudo , enquanto programadores que trabalham em um projeto pequeno, sugere que os desenvolvedores que usam TDD produzem código com melhor cobertura de teste do que aqueles que testam após o fato (92% -98% vs 80% -90%) e, consequentemente, capturam mais defeitos durante o desenvolvimento (18% menos defeitos encontrados no código produzido usando TDD).
Jules
11

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.

Edward Strange
fonte
+1 Obrigado pela resposta abrangente, Noah. Concordo que a principal diferença entre TDD e não-TDD ocorre quando os testes são escritos. No entanto, também acho que o primeiro "D" no TDD significa "driven", o que significa que, no TDD, todo o desenvolvimento é impulsionado pelo teste. É isso que acho mais intrigante. Não tenho problemas em escrever testes antes de realmente construir o que será testado. Mas deixar os testes dirigirem? Como é diferente de uma luz verde fazer algo desde que o superficial (ou seja, o resultado) seja bom?
CesarGon
Bem, Cesar, o que você propõe como um critério melhor e objetivo para decidir quando uma tarefa de desenvolvimento é concluída? Se, como no TDD, o teste é a especificação que um desenvolvedor visa, então o desenvolvedor fez seu trabalho quando o teste passou, não? Sim, pode haver falhas no teste, assim como em qualquer especificação. Essa não é a tarefa dos desenvolvedores a resolver. Se o teste for defeituoso, ele será corrigido, o desenvolvimento terá como alvo o novo alvo e, quando estiver tudo verde, eles serão concluídos. Funciona porque SEMPRE existe um teste a ser aprovado ... nenhum fluff extra e sem documentos.
Edward Strange
3
Talvez eu não tenha me expressado claramente. Os testes podem ser uma boa maneira de determinar quando você termina. Mas não acho que eles sejam uma boa maneira de decidir o que você deve construir. E, no TDD, acho que as pessoas estão usando testes para decidir o que devem construir. Essa é a sua experiência também?
precisa saber é o seguinte
Não. Nossas construções são automatizadas. Eles são desencadeados por mudanças. Como eu disse, o TDD é apenas parte da solução.
Edward Strange
9

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.

Newtopian
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 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.

Alva
fonte
2
Eu gosto disso - enfatiza o ponto de que não é tanto o TDD que cria os benefícios (embora os testes de unidade tenham claramente uma enorme quantidade de valor) quanto o tipo de código que ele produz no sentido de ser testável (isoladamente) e todos os tipos de coisas boas resultam disso (separação de preocupações, IoC e injeção de dependência, etc, etc)
Murph
1
@Murph sim TDD ajuda a mantê-lo :) honesto
Alb
1
Para ser sincero, não estou realmente convencido pelo argumento "mais fácil de acelerar" - os testes podem ser úteis, mas o código (como um todo, não necessariamente isolado) pode ser um pouco mais difícil de decodificar, pois algumas coisas parece que por mágica, por exemplo, você não sabe qual implementação do IInjectedThing você está usando.
Murph
@ Murph A teoria é que a implementação IInjectedThing também foi projetada bem e coberta por bons testes, então você realmente não precisa saber o que é ser capaz de entender uma classe na qual é injetada.
Adam Lear
@ Anna - sim, até certo ponto ... se você está tentando descobrir onde algo está quebrado (eu sempre sinto que a caça a bugs é uma boa maneira de encontrar pessoas que estão em um projeto) ou onde algo precisa ser alterado / adicionado você precisa saber onde. Mesmo que esse local esteja bem encapsulado, você ainda precisa encontrá-lo ... e se isso significa substituir algo (nova implementação do IWhatsit), você precisa saber como usar a implementação alternativa. Mais uma vez, não estou impedindo que a construção seja ruim - muitas evidências em contrário -, mas sugerindo que algumas coisas podem ser menos óbvias.
Murph
5

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.

Maglob
fonte
+1 Acho que você acertou em cheio, Maglob. Eu particularmente gosto da sua explicação de que "o TDD ajuda a eliminar as piores partes e hábitos, [...] aumentando indiretamente a qualidade". E a analogia da barba longa também é muito boa.
CesarGon
você não escreve testes para um código incorreto, mas escreve um teste e depois escreve o código para fazer o teste passar.
Maglob, pelo amor ao lado mais prático das coisas, você o cobre melhor. @ Thorbjørn, acho que o Maglob estava seguindo mais adiante que, se o seu projeto projetado for ruim, seus testes certamente terão que absorver diretamente o nível de sujeira que você está tentando materializar e o cheiro podre dele deve cheirar nos seus testes antes você até escreve qualquer código real.
Filip Dupanović 31/01
3

A abordagem "teste de gravação + refatoração até aprovação" parece incrivelmente anti-engenharia.

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

A refatoração de código é o processo de alterar o código-fonte de um programa de computador sem modificar seu comportamento funcional externo, a fim de melhorar alguns dos atributos não funcionais do software.

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.

back2dos
fonte
Eu não acho que tenho um equívoco; Concordo com a definição de refatoração de código que você postou, mas também acho que é necessário analisar a granularidade das alterações no código. Quando você diz "o processo de alterar o código-fonte de um programa de computador", precisa entender que, da perspectiva de um determinado todo, o comportamento não muda, mas o comportamento das partes realmente muda. É assim que a mudança é realizada. Além disso, ouvi você falar sobre por que o TDD funciona (e eu o compartilho), mas como a arquitetura é abordada de acordo com o meu post original?
CesarGon
@ CesarGon: Postagem atualizada.
jan2
2

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.

sevenseacat
fonte
Eu ouvi você sobre os benefícios que você reivindica para TDD. Mas, pelo que entendi, você não trata dos problemas de arquitetura e qualidade de teste que solicito explicitamente na minha pergunta.
CesarGon
@ CesarGon: Eu acho que suas perguntas específicas se aplicam a qualquer tipo de teste, não apenas ao TDD. Então, eu apenas me concentrei nos recursos específicos do TDD que 'funcionam'.
sevenseacat
1
Os testes de integração definitivamente fazem mais sentido do que os testes de unidade independentes. A maioria dos casos de erros que encontrei nunca foram encontrados em testes de unidade, apenas testando todo o sistema real com todos os parafusos e assobios no lugar.
2

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).

Filip Dupanović
fonte
+1 para uma boa explicação do meu primeiro ponto e para a referência a Hank Moody. Glorioso.
CesarGon
2
Obrigado, agradeço. Eu vejo o TDD mais como um fenômeno psicológico, ao invés de uma abordagem / processo técnico. Mas essa é apenas a minha visão de mundo sobre o assunto.
Filip Dupanović 31/01
Você sabe exatamente quantos banheiros e onde eles devem ser colocados? A resposta é sim - pergunte a qualquer arquiteto e eles dirão que essas informações são feitas antecipadamente e, às vezes, com dados estatísticos claros para fazer o backup.
Gbjbaanb # 14/13
1

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 ...

Ernelli
fonte
Eu discordo de sua implicação de que é fácil em sistemas físicos (ou seja, que não sejam de software) reproduzir falhas. Veja o trabalho extremamente complexo e árduo necessário para determinar as causas principais das falhas mecânicas nos acidentes de trânsito aéreo, por exemplo.
CesarGon
Hm, agora você está comparando um avião comercial com uma ponte que falha; uma ponte geralmente não pode voar, caso encerrado. Mas a comparação entre aviões e software às vezes é válida. Ambas as áreas são muito complexas e requerem uma metodologia de teste estruturada. Portanto, quando uma ponte falha, você sabe que foi sobrecarregada. Quando um avião cai, você sabe que o estado anormal de voar acima do solo falhou, mas o motivo geralmente requer uma investigação completa da mesma forma que a falha do software.
Ernelli 12/02
As pontes podem ser duplicadas - ou pelo menos, o modelo de ponte que você compra do arquiteto pode, aproximadamente, com modificações para se adequar às suas circunstâncias exatas. O ponto é que, se você precisar de uma ponte, irá até o arquiteto e ele fornecerá uma lista de apenas alguns tipos que você pode ter - suspensão, caixa, arco etc., e uma lista limitada de materiais para construí-la.
gbjbaanb 14/09
1

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.

SnoopDougieDoug
fonte
1
Você tem alguma evidência de que erros foram encontrados antes em uma configuração de TDD? Além disso, e os efeitos colaterais do TDD, como o impacto na arquitetura?
CesarGon
0

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.

Marcie
fonte
6
-1. Muitas pessoas continuam dizendo isso, mas ainda tenho que ver a mágica que faz isso acontecer.
Bart van Ingen Schenau
@Bart van Ingen Schenau, você já fez TDD? Eu faço isso há cerca de 4 anos e definitivamente vi a "mágica" acontecer.
Marcie
0

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
0

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.

CodeART
fonte
0

Por que o TDD funciona?

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.

Cola
fonte