¿Los simulacros violan el principio de Abierto / Cerrado?

13

Hace un tiempo leí, en una respuesta de desbordamiento de pila que no puedo encontrar, una oración que explicaba que debería probar API públicas, y el autor dijo que debería probar interfaces. El autor también explicó que si cambia la implementación de un método, no debería necesitar modificar el caso de prueba, ya que al hacerlo se rompería el contrato que hace que el sistema bajo prueba funcione. En otras palabras, una prueba debería fallar si el método no funciona, pero no porque la implementación haya cambiado.

Esto me llamó la atención cuando hablamos de burlas. Dado que la burla depende en gran medida de las llamadas de expectativa del sistema bajo las dependencias de prueba, las simulaciones están estrechamente relacionadas con la implementación en lugar de la interfaz.

Mientras investiga simulacro frente a talón , varios artículos coinciden en que se deben usar talones en lugar de simulacros, ya que no dependen de las expectativas de las dependencias, lo que significa que la prueba no necesita conocer el sistema subyacente. implementación de prueba.

Mis preguntas serían:

  1. ¿Los simulacros violan el principio de apertura / cierre?
  2. ¿Falta algo en el argumento a favor de los talones en el último párrafo, que hace que los talones no sean tan buenos vs simulacros?
  3. Si es así, ¿cuándo sería un buen caso de uso para burlarse y cuándo sería un buen caso de uso para usar talones?
pregunta Christopher Francisco 12.08.2015 - 23:28

4 respuestas

4
  1. No veo por qué los simulacros violarían el principio de abrir / cerrar. Si puede explicarnos por qué cree que podrían hacerlo, entonces podremos aliviar sus inquietudes.

  2. La única desventaja de los stubs en los que puedo pensar es que generalmente requieren más trabajo para escribir que los mocks, ya que cada uno de ellos es en realidad una implementación alternativa de una interfaz dependiente, por lo que generalmente tiene que proporcionar una Implementación completa (o convincentemente completa) de la interfaz dependiente. Para darle un ejemplo extremo, si su subsistema bajo prueba invoca un RDBMS, entonces una simulación del RDBMS simplemente respondería a consultas específicas que se sabe que emitió el subsistema bajo prueba, produciendo conjuntos predeterminados de datos de prueba. Por otro lado, una implementación alternativa sería un RDBMS en memoria completo, posiblemente con la carga adicional de tener que emular las peculiaridades del RDBMS cliente-servidor real que está utilizando en producción. (Por suerte, tenemos cosas como HSQLDB, así que podemos hacer eso, pero aún así, es un poco complicado, especialmente porque se adhiere al estándar SQL y no se molesta en emular las peculiaridades de nadie).

  3. Los buenos casos de uso para burlarse son cuando la interfaz dependiente es demasiado complicada para escribir una implementación alternativa, o si está seguro de que solo escribirá el simulacro una vez y nunca lo volverá a tocar. En estos casos, siga adelante y utilice un simulacro rápido y sucio. En consecuencia, los buenos casos de uso de apéndices (implementaciones alternativas) son prácticamente todo lo demás. Especialmente si prevé entablar una relación a largo plazo con el subsistema bajo prueba, definitivamente elija una implementación alternativa que sea agradable y limpia, y que requiera mantenimiento solo en caso de que la interfaz cambie, en lugar de requerir mantenimiento siempre que la interfaz cambia y siempre que cambie la implementación del subsistema bajo prueba.

P.S. La persona a la que se refiere podría haber sido yo, en una de mis otras respuestas relacionadas con las pruebas aquí en programmers.stackexchange.com, por ejemplo, este .

    
respondido por el Mike Nakis 13.08.2015 - 03:54
9
  1. El principio Abrir / Cerrado se trata principalmente de poder cambiar el comportamiento de una clase sin modificarlo. Por lo tanto, inyectar una dependencia de componente simulada dentro de una clase bajo prueba no la viola.

  2. El problema con los dobles de prueba (simulacro / esbozo) es que básicamente se hacen suposiciones arbitrarias con respecto a cómo la clase bajo prueba interactúa con su entorno. Si esas expectativas son erróneas, es probable que tenga algunos problemas una vez que se implemente el código. Si puede permitírselo, pruebe su código dentro de las mismas restricciones que la que limita su entorno de producción. Si no puede, haga las menores suposiciones posibles y simule / apague solo los periféricos de su sistema (base de datos, servicio de autenticación, cliente HTTP, etc.).

La única razón válida por la cual, IMHO, se debe usar un doble, es cuando necesita registrar sus interacciones con la clase bajo prueba, o cuando necesita proporcionar datos falsos (lo que pueden hacer ambas técnicas). Sin embargo, tenga cuidado, si abusa de él refleja un mal diseño o una prueba que se basa demasiado en la API en la implementación de la prueba.

    
respondido por el Francis Toth 12.08.2015 - 23:55
6

Nota: Supongo que está definiendo que Simulacro significa "una clase sin implementación, solo algo que puede monitorear" y que Stub es "simulado parcial, también conocido como parte del comportamiento real de la clase implementada", como por esta pregunta de desbordamiento de pila .

No estoy seguro de por qué crees que el consenso es usar talones, por ejemplo, es todo lo contrario en Documentación de Mockito

  

Como de costumbre, leerá la advertencia parcial simulada: la programación orientada a objetos es más difícil de abordar la complejidad al dividir la complejidad en objetos SRPy separados y específicos. ¿Cómo encaja el simulacro parcial en este paradigma? Bueno, simplemente no ... El simulacro parcial generalmente significa que la complejidad se ha movido a un método diferente en el mismo objeto. En la mayoría de los casos, esta no es la forma en que desea diseñar su aplicación.

     

Sin embargo, hay casos raros en que las simulaciones parciales son útiles: tratar con el código que no se puede cambiar fácilmente (interfaces de terceros, refactorización interina del código heredado, etc.) Sin embargo, no usaría las simulaciones parciales para nuevos &erio; código bien diseñado.

Esa documentación lo dice mejor que yo. El uso de simulacros le permite solo probar una clase en particular y nada más; Si necesita simulaciones parciales para lograr el comportamiento que está buscando, probablemente haya hecho algo mal, esté violando el SRP, etc., y su código podría ser un refactor. Los simulacros no no violan el principio de apertura-cierre, ya que de todos modos solo se usan en pruebas, no son cambios reales en ese código. Por lo general, se generan sobre la marcha de todos modos por una biblioteca como cglib.

    
respondido por el durron597 12.08.2015 - 23:45
2

Creo que el problema puede surgir de la suposición de que las únicas pruebas válidas son aquellas que cumplen con la prueba abierta / cerrada.

Es fácil ver que la única prueba que debería importar es la que prueba la interfaz. Sin embargo, en realidad, a menudo es más efectivo probar esa interfaz al probar el funcionamiento interno.

Por ejemplo, es casi imposible probar cualquier requisito negativo, como "la implementación no generará ninguna excepción". Considere la posibilidad de implementar una interfaz de mapa con un hashmap. Desea estar seguro de que el mapa hash se encuentra con la interfaz del mapa, sin lanzarlo, incluso cuando tiene que repetir las cosas (lo que podría resultar peligroso). Puede probar cada combinación de entradas para asegurarse de que cumplan con los requisitos de la interfaz, pero eso podría llevar más tiempo que la muerte térmica del universo. En su lugar, rompes un poco la encapsulación y desarrollas simulaciones que interactúan más estrechamente, lo que obliga al hashmap a hacer exactamente el refrito necesario para garantizar que el algoritmo de reinicio no se ejecute.

Tl / Dr: hacerlo "por el libro" está bien, pero cuando llega el momento, tener un producto en la mesa de tu jefe para el viernes es más útil que un conjunto de pruebas de by-the-book que lleva hasta el calor Muerte del universo para confirmar conformidad.

    
respondido por el Cort Ammon 13.08.2015 - 03:51

Lea otras preguntas en las etiquetas