Digamos que comienzo a desarrollar un juego de roles con personajes que atacan a otros personajes y ese tipo de cosas.
Aplicando TDD, hago algunos casos de prueba para probar la lógica dentro del Character.receiveAttack(Int)
método. Algo como esto:
@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 tengo 10 métodos de prueba receiveAttack
. Ahora, agrego un método Character.attack(Character)
(que llama receiveAttack
método), y después de algunos ciclos de TDD probándolo, tomo una decisión: Character.receiveAttack(Int)
debería ser private
.
¿Qué sucede con los 10 casos de prueba anteriores? ¿Debo eliminarlos? ¿Debo mantener el método public
(no lo creo)?
Esta pregunta no trata sobre cómo probar métodos privados, sino cómo tratarlos después de un rediseño al aplicar TDD
object-oriented-design
tdd
Héctor
fuente
fuente
internal
o el equivalente de su idioma para evitar que quede expuesta. De hecho, la respuesta de Kevin Cline es este tipo de enfoque.Respuestas:
En TDD, las pruebas sirven como documentación ejecutable de su diseño. Su diseño cambió, así que, obviamente, ¡su documentación también debe hacerlo!
Tenga en cuenta que, en TDD, la única forma en que
attack
podría haber aparecido el método es como resultado de pasar una prueba fallida. Lo que significa queattack
está siendo probado por alguna otra prueba. Lo que significa que indirectamentereceiveAttack
está cubierto porattack
las pruebas de. Idealmente, cualquier cambio areceiveAttack
debería romper al menos una deattack
las pruebas.Y si no es así, ¡hay una funcionalidad
receiveAttack
que ya no es necesaria y ya no debería existir!Entonces, dado
receiveAttack
que ya se ha probadoattack
, no importa si mantiene o no sus pruebas. Si su marco de prueba facilita la prueba de métodos privados, y si decide probar métodos privados, puede conservarlos. Pero también puede eliminarlos sin perder la cobertura de prueba y la confianza.fuente
Si el método es lo suficientemente complejo como para necesitar pruebas, debería ser público en alguna clase. Entonces refactoriza desde:
a:
Mueva la prueba actual para X.complexity a ComplexityTest. Luego envía un mensaje de texto a X burlándose de Complejidad.
En mi experiencia, refactorizar hacia clases más pequeñas y métodos más cortos ofrece enormes beneficios. Son más fáciles de entender, más fáciles de probar y terminan siendo reutilizados más de lo que cabría esperar.
fuente
this.health = this.health - attackDamage
). Quizás extraerlo a otra clase es una solución de ingeniería excesiva, para este momento.Algo a tener en cuenta aquí es que la decisión que está tomando es eliminar un método de la API . Las cortesías de la compatibilidad con versiones anteriores sugerirían
Las pruebas se eliminan o reemplazan cuando su API ya no admite el método. En ese momento, el método privado es un detalle de implementación que debería poder refactorizar.
En ese punto, regresa a la pregunta estándar de si su conjunto de pruebas debe acceder directamente a las implementaciones, en lugar de interactuar únicamente a través de la API pública. Un método privado es algo que deberíamos poder reemplazar sin que el conjunto de pruebas se interponga en el camino . Por lo tanto, esperaría que las pruebas se eliminen, ya sea que se retiren o se trasladen con la implementación a un componente que se pueda probar por separado.
fuente