python unit-testing oop language-agnostic private

python - ¿Debería probar el método privado/protegido?



unit-testing oop (3)

Al realizar pruebas, debe centrarse en el comportamiento externo de su código, no en los detalles de la implementación. No sé el contexto, así que haré algunas suposiciones enormes aquí.

¿Realmente te importa el comportamiento de una superclase de mamíferos (potencialmente abstracta)? ¿Es importante la relación de reutilización a través de la herencia? ¿Qué sucede si decide reemplazar la relación de herencia con una estrategia basada en la composición?

Me concentraría en probar el comportamiento de las clases que realmente te interesan: "¿Come un tigre como se espera?" En lugar de probar alguna superclase abstracta que solo se introduce para la reutilización del código.

Esto es en realidad el lenguaje agnóstico. Pero te daré contexto en python.

Tengo esta clase de padres

class Mammal(object): def __init__(self): """ do some work """ def eat(self, food): """Eat the food""" way_to_eat = self._eating_method() self._consume(food) def _eating_method(self): """Template method""" def _consume(self, food): """Template method"""

Aquí eat es el único método público, mientras que _consume y _eating_method son en realidad métodos protegidos que serán implementados por clases secundarias.

¿Qué probarás cuando hayas escrito solo la clase de Mammal ?

Obviamente los 4 métodos.

Ahora presentemos un niño

class Tiger(Mammal): def _eating_method(self): """Template method""" def _consume(self, food): """Template method"""

Mira esta clase Tiene solo 2 métodos protegidos .

¿Debo probar los 4 métodos de Tiger (incluidos 2 heredados) o simplemente probar los cambios introducidos (solo los 2 métodos anulados)?

¿Cuál es el caso ideal?


La forma en que abordaría esto es:

  • Cree una subclase comprobable mínima de Mammal que proporcione implementaciones mínimas de los dos métodos protegidos que le permitan realizar pruebas unitarias del comportamiento de los métodos públicos.
  • Escriba pruebas unitarias separadas para cada subclase que nuevamente prueban los métodos públicos en Mammal , pero están afirmando el comportamiento que es específico de esa subclase.

Esto debería proporcionarle la cobertura de prueba necesaria con un número mínimo de pruebas.

Un enfoque alternativo sería probar solo las subclases, y en una de las pruebas de unidad de subclase también se deben establecer las características específicas de Mammal . Esto evita la necesidad de crear una subclase de prueba específica, sin embargo, dos desventajas son:

  • Ya no está probando Mammal de forma aislada y, por lo tanto, las pruebas en el código específico de Mammal son susceptibles de fallar debido a problemas en la subclase.
  • Puede ser menos obvio para otros cómo y dónde se están probando las propiedades de los Mammal .

Desde un punto de vista teórico , solo necesita probar los métodos públicos de sus clases creables (en idiomas estándar OOP). No tiene sentido probar el comportamiento interno porque lo único que desea es "qué salida para esa entrada" (para un método en particular o para toda la clase). Debe intentar respetarlo todo lo que pueda, ya que lo obliga a hacer algunas preguntas sobre la encapsulation de su clase y la interfaz proporcionada, que puede ser decisiva para su arquitectura.

Desde un punto de vista pragmático , a veces puede tener algunas clases de ayuda abstractas sin una subclase concreta implementada o una clase abstracta que incluya el 90% de sus clases secundarias y donde sería demasiado difícil probar la salida sin conectarse a un método protegido. En ese tipo de casos, puedes mock una subclase.

En su ejemplo directo, le sugeriría que solo pruebe la clase Tiger (y solo el método público eat ).

Solo una nota para la gente que piensa en TDD . En TDD, no deberías haber empezado a codificar la clase Mammal antes que la clase Tiger porque Mammal debería ser el resultado de una fase de refactorización. Entonces, ciertamente no tienes ninguna prueba específica para Mammal .