Digamos que eu comece a desenvolver um RPG com personagens que atacam outros personagens e esse tipo de coisa.
Aplicando o TDD, faço alguns casos de teste para testar a lógica dentro do Character.receiveAttack(Int)
método. Algo assim:
@Test
fun healthIsReducedWhenCharacterIsAttacked() {
val c = Character(100) //arg is the health
c.receiveAttack(50) //arg is the suffered attack damage
assertThat(c.health, is(50));
}
Digamos que eu tenha 10 métodos, receiveAttack
método de teste . Agora, adiciono um método Character.attack(Character)
(que chama receiveAttack
método) e, após alguns ciclos de TDD testá-lo, tomo uma decisão: Character.receiveAttack(Int)
deveria private
.
O que acontece com os 10 casos de teste anteriores? Devo excluí-los? Devo manter o método public
(acho que não)?
Esta questão não é sobre como testar métodos privados, mas como lidar com eles após um novo design ao aplicar o TDD
object-oriented-design
tdd
Hector
fonte
fonte
internal
ou equivalente ao seu idioma para impedir que seja exposta. De fato, a resposta de Kevin Cline é esse tipo de abordagem.Respostas:
No TDD, os testes servem como documentação executável do seu design. Seu design mudou, portanto, obviamente, sua documentação também deve!
Observe que, no TDD, a única maneira pela qual o
attack
método poderia ter aparecido é o resultado de uma reprovação no teste. O que significa queattack
está sendo testado por algum outro teste. O que significa que indiretamentereceiveAttack
é coberto pelosattack
testes de. Idealmente, qualquer alteraçãoreceiveAttack
deve interromper pelo menos um dosattack
testes.E, se isso não acontecer, existe uma funcionalidade
receiveAttack
que não é mais necessária e não deve mais existir!Portanto, como
receiveAttack
já foi testadoattack
, não importa se você mantém ou não os testes. Se sua estrutura de teste facilitar o teste de métodos particulares, e se você decidir testar métodos particulares, poderá mantê-los. Mas você também pode excluí-los sem perder a cobertura e a confiança do teste.fonte
Se o método for complexo o suficiente para precisar de teste, ele deve ser público em alguma classe. Então você refatora de:
para:
Mova o teste atual para X.complexity para ComplexityTest. Em seguida, envie um texto para X.something zombando da Complexidade.
Na minha experiência, a refatoração para classes menores e métodos mais curtos traz enormes benefícios. Eles são mais fáceis de entender, mais fáceis de testar e acabam sendo reutilizados mais do que se poderia esperar.
fonte
this.health = this.health - attackDamage
). Talvez extraí-lo para outra classe seja uma solução com excesso de engenharia, para este momento.Algo a ter em mente aqui é que a decisão que você está tomando é remover um método da API . As cortesias de compatibilidade com versões anteriores sugeririam
Os testes são removidos / ou substituídos quando sua API não oferece mais suporte ao método. Nesse ponto, o método privado é um detalhe de implementação que você deve poder refatorar.
Nesse ponto, você está de volta à questão padrão de saber se o seu conjunto de testes deve acessar diretamente implementações, em vez de interagir puramente por meio da API pública. Um método privado é algo que poderíamos substituir sem que a suíte de testes atrapalhasse . Então, eu esperaria que os testes em questão desaparecessem - sendo aposentados ou movendo-se com a implementação para um componente testável separadamente.
fonte