Estas são as regras de Robert C. Martin para TDD :
- Você não tem permissão para escrever nenhum código de produção, a menos que seja aprovado no teste de unidade.
- Você não tem permissão para escrever mais testes de unidade que o suficiente para falhar; e falhas de compilação são falhas.
- Você não tem permissão para escrever mais código de produção que o suficiente para passar no único teste de unidade com falha.
Quando escrevo um teste que parece valer a pena, mas passa sem alterar o código de produção:
- Isso significa que fiz algo errado?
- Devo evitar escrever esses testes no futuro, se puder ser ajudado?
- Devo deixar esse teste lá ou removê-lo?
Nota: Eu estava tentando fazer esta pergunta aqui: Posso começar com um teste de unidade aprovado? Mas eu não era capaz de articular a questão suficientemente bem até agora.
testing
unit-testing
tdd
Daniel Kaplan
fonte
fonte
Respostas:
Ele diz que você não pode escrever código de produção, a menos que seja aprovado em um teste de unidade com falha, não que você não possa escrever um teste que passe desde o início. A intenção da regra é dizer "Se você precisar editar o código de produção, certifique-se de escrever ou alterar um teste primeiro".
Às vezes, escrevemos testes para provar uma teoria. O teste passa e isso desmente a nossa teoria. Não removemos o teste. No entanto, podemos (sabendo que temos o suporte do controle de origem) interromper o código de produção, para ter certeza de que entendemos por que passou quando não esperávamos.
Se for um teste válido e correto, e não estiver duplicando um teste existente, deixe-o lá.
fonte
Isso significa que:
A última situação é mais comum do que você imagina. Como um exemplo completamente ilusório e trivial (mas ainda ilustrativo), digamos que você escreveu o seguinte teste de unidade (pseudocódigo, porque sou preguiçoso):
Porque tudo o que você realmente precisa é o resultado de 2 e 3 somados.
Seu método de implementação seria:
Mas vamos dizer que agora preciso adicionar 4 e 6:
Não preciso reescrever meu método, porque ele já cobre o segundo caso.
Agora, digamos que descobri que minha função Adicionar realmente precisa retornar um número que tenha algum limite, digamos 100. Posso escrever um novo método que testa isso:
E este teste agora falhará. Agora devo reescrever minha função
para fazer passar.
O senso comum determina que, se
passa, você não deliberadamente faz com que seu método falhe, apenas para que você possa ter um teste com falha e escrever um novo código para fazer esse teste passar.
fonte
add(2,3)
passar, você literalmente retornaria 5. Codificado. Em seguida, você escreveria o teste para oadd(4,6)
qual forçaria a escrever o código de produção que faz com que seja aprovado sem quebraradd(2,3)
ao mesmo tempo. Você iria acabar comreturn x + y
, mas você não iria começar com ele. Em teoria. Naturalmente, Martin (ou talvez fosse outra pessoa, não me lembro) gosta de fornecer exemplos de educação, mas não espera que você realmente escreva esse código trivial dessa maneira.Seu teste passou, mas você não está errado. Eu acho que aconteceu porque o código de produção não é TDD desde o início.
Suponhamos TDD canônico (?). Não há código de produção, mas alguns casos de teste (é claro que sempre falham). Nós adicionamos código de produção para passar. Então pare aqui para adicionar mais casos de teste de falha. Adicione novamente o código de produção para passar.
Em outras palavras, seu teste pode ser um tipo de teste de funcionalidade, não um simples teste de unidade TDD. Esses são sempre ativos valiosos para a qualidade do produto.
Pessoalmente, não gosto de regras totalitárias e desumanas;
fonte
Na verdade, o mesmo problema surgiu em um dojo na noite passada.
Eu fiz uma pesquisa rápida sobre isso. Isto é o que eu vim com:
Basicamente, não é proibido explicitamente pelas regras do TDD. Talvez sejam necessários alguns testes adicionais para provar que uma função funciona corretamente para uma entrada generalizada. Nesse caso, a prática de TDD é deixada de lado por pouco tempo. Observe que deixar a prática do TDD em breve não necessariamente quebra as regras do TDD, desde que não haja um código de produção adicionado nesse meio tempo.
Testes adicionais podem ser escritos desde que não sejam redundantes. Uma boa prática seria fazer o teste de particionamento de classe de equivalência. Isso significa que os casos de borda e pelo menos um caso interno para cada classe de equivalência são testados.
Um problema que pode ocorrer com essa abordagem, porém, é que, se os testes forem aprovados desde o início, não será possível garantir que não haja falsos positivos. Significando que pode haver testes que passam porque os testes não foram implementados corretamente e não porque o código de produção está funcionando corretamente. Para evitar isso, o código de produção deve ser ligeiramente alterado para interromper o teste. Se isso fizer com que o teste falhe, é provável que o teste seja implementado corretamente e o código de produção possa ser alterado novamente para que o teste passe novamente.
Se você quiser praticar TDD estrito, talvez não escreva nenhum teste adicional que seja aprovado desde o início. Por outro lado, em um ambiente de desenvolvimento corporativo, na verdade, devemos abandonar a prática de TDD se testes adicionais parecerem úteis.
fonte
Um teste que passa sem modificar o código de produção não é inerentemente ruim e geralmente é necessário para descrever um requisito adicional ou caso limite. Enquanto seu teste "parecer valer a pena", como você diz que o seu faz, mantenha-o.
O problema é quando você escreve um teste que já está passando como um substituto para realmente entender o espaço do problema.
Podemos imaginar em dois extremos: um programador que escreve um grande número de testes "apenas no caso" de um erro; e um segundo programador que analisa cuidadosamente o espaço do problema antes de escrever um número mínimo de testes. Digamos que ambos estão tentando implementar uma função de valor absoluto.
O primeiro programador escreve:
O segundo programador escreve:
A implementação do primeiro programador pode resultar em:
A implementação do segundo programador pode resultar em:
Todos os testes são aprovados, mas o primeiro programador não apenas escreveu vários testes redundantes (diminuindo desnecessariamente o ciclo de desenvolvimento), como também falhou ao testar um caso de limite (
abs(0)
).Se você se encontra escrevendo testes que passam sem modificar o código de produção, pergunte a si mesmo se seus testes estão realmente agregando valor ou se precisa gastar mais tempo entendendo o espaço do problema.
fonte
abs(n) = n*n
e passou.abs(-2)
. Como em tudo, moderação é a chave.