Esta pode ser uma pergunta bastante boba, como estou nas minhas primeiras tentativas no TDD. Adorei o senso de confiança que ele traz e a estrutura geralmente melhor do meu código, mas quando comecei a aplicá-lo em algo maior que os exemplos de brinquedos de uma classe, tive dificuldades.
Suponha que você esteja escrevendo uma espécie de biblioteca. Você sabe o que tem de fazer, conhece uma maneira geral de como ela deve ser implementada (arquitetura), mas continua "descobrindo" que precisa fazer alterações em sua API pública à medida que codifica. Talvez você precise transformar esse método privado em padrão de estratégia (e agora precise passar por uma estratégia ridicularizada em seus testes), talvez tenha extraviado uma responsabilidade aqui e ali e dividido uma classe existente.
Quando você está aprimorando o código existente, o TDD parece realmente bom, mas quando você está escrevendo tudo do zero, a API para a qual você escreve testes é um pouco "embaçada", a menos que você faça um grande projeto com antecedência. O que você faz quando já possui 30 testes no método que teve sua assinatura (e para essa parte, comportamento) alterada? São muitos os testes a serem alterados após a adição.
Respostas:
O que você chama de "grande design antecipadamente" , chamo de "planejamento sensato da sua arquitetura de classe".
Você não pode aumentar uma arquitetura a partir de testes de unidade. Até o tio Bob diz isso.
http://s3.amazonaws.com/hanselminutes/hanselminutes_0171.pdf , Página 4
Eu acho que seria mais sensato abordar o TDD a partir de uma perspectiva de validação do seu projeto estrutural. Como você sabe que o design está incorreto se você não testá-lo? E como você verifica se suas alterações estão corretas sem alterar também os testes originais?
O software é "flexível" precisamente porque está sujeito a alterações. Se você não se sentir à vontade com a quantidade de alterações, continue ganhando experiência em design de arquitetura e o número de alterações que você precisará fazer nas arquiteturas de aplicativos diminuirá com o tempo.
fonte
Se você faz TDD. Você não pode alterar a assinatura e o comportamento sem conduzi-lo por testes. Portanto, os 30 testes que falharam foram excluídos no processo ou alterados / refatorados junto com o código. Ou agora estão obsoletos, seguros para excluir.
Você não pode ignorar o vermelho 30 vezes no seu ciclo de refatoração de vermelho-verde?
Seus testes devem ser refatorados ao lado do seu código de produção. Se você puder, execute novamente todos os testes após cada alteração.
Não tenha medo de excluir os testes TDD. Alguns testes acabam testando blocos de construção para chegar ao resultado desejado. O resultado desejado em um nível funcional é o que conta. Testes em torno de etapas intermediárias no algoritmo que você escolheu / inventou podem ou não ter muito valor quando há mais de uma maneira de alcançar o resultado ou você se deparou com um beco sem saída.
Às vezes, você pode criar alguns testes de integração decentes, mantê-los e excluir o restante. Depende um pouco se você trabalha de dentro para fora ou de cima para baixo e quão grandes medidas você dá.
fonte
Como Robert Harvey acabou de dizer, você provavelmente está tentando usar o TDD para algo que deve ser tratado por uma ferramenta conceitual diferente (ou seja: "design" ou "modelagem").
Tente projetar (ou "modelar") seu sistema de maneira bastante abstrata ("geral", "vaga"). Por exemplo, se você tiver que modelar um carro, basta ter uma classe de carro com algum método e campo vago, como startEngine () e assentos int. Ou seja: descreva o que você deseja expor ao público , não como deseja implementá-lo. Tente expor apenas funcionalidades básicas (ler, escrever, iniciar, parar, etc) e deixar o código do cliente elaborado (prepareMyScene (), killTheEnemy (), etc).
Anote seus testes assumindo essa interface pública simples.
Mude o comportamento interno de suas classes e métodos sempre que precisar.
Se e quando você precisar alterar sua interface pública e seu conjunto de testes, pare e pense. Provavelmente, isso é um sinal de que há algo errado na sua API e no seu design / modelagem.
Não é incomum alterar uma API. A maioria dos sistemas em sua versão 1.0 adverte explicitamente os programadores / usuários contra possíveis alterações em sua API. Apesar disso, um fluxo contínuo e descontrolado de alterações na API é um sinal claro de projeto ruim (ou totalmente ausente).
BTW: Normalmente, você deve ter apenas alguns testes por método. Um método, por definição, deve implementar uma "ação" claramente definida em algum tipo de dados. Em um mundo perfeito, essa deve ser uma ação única que corresponde a um único teste. No mundo real, não é incomum (e não está errado) ter poucas "versões" diferentes da mesma ação e poucos testes correspondentes diferentes. Com certeza, você deve evitar 30 testes no mesmo método. Este é um sinal claro de que o método tenta fazer muito (e seu código interno fica fora de controle).
fonte
Eu olho para ele da perspectiva do usuário. Por exemplo, se suas APIs me permitirem criar um objeto Person com nome e idade, é melhor que haja um construtor Person (nome da string, int age) e métodos de acessador para nome e idade. É simples criar casos de teste para novas pessoas com e sem nome e idade.
doug
fonte