Como tudo o que vem sob o banner "Ágil", TDD é algo que soa bem na teoria, mas na prática não é tão claro como é bom (e também como a maioria das coisas "ágeis", você é informado que se não goste, você está fazendo errado).
A definição de TDD não está gravada na pedra: caras como Kent Beck exigem que um teste de não-compilação deve ser escrito antes de uma única linha de código e cada linha de código deve ser escrita para passar em um teste com falha. O design frontal é mínimo e tudo é dirigido pelos testes. Isso simplesmente não funciona. Eu vi um grande aplicativo corporativo desenvolvido usando essa metodologia e espero que seja o pior código que eu vejo na minha carreira (não vai estar longe; e isso apesar de ter alguns desenvolvedores talentosos trabalhando nisso). Pelo que eu vi isso resulta em um grande número de testes mal pensados que validam principalmente que chamadas de função ocorrem, que exceções são lançadas quando as variáveis são nulas e a estrutura de simulação recebe um treino completo (whoop-de-whoop); seu código de produção fica strongmente acoplado a esses testes e o sonho de refatoração constante e fácil não aparece - na verdade, as pessoas são menos propensas a corrigir códigos ruins por causa de todos os testes que serão quebrados. Nesse tipo de ambiente, os gerentes de software preferem ter software ruim com testes de aprovação e alta cobertura de código do que um bom software com menos testes.
Por outro lado, ouvi pessoas argumentarem que o TDD significa projetar os testes antecipadamente em um alto nível como parte da fase de planejamento - juntamente com o projeto arquitetônico. Esses testes podem mudar durante o desenvolvimento à medida que mais informações se tornam disponíveis, mas foram cuidadosamente considerados e oferecem um bom guia sobre o que o código deve realmente fazer. Para mim, isso faz todo o sentido.