En Pruebas unitarias, ¿por qué debería crear un Repositorio dos veces?

10

El otro día estaba leyendo un poco sobre Unit Testing y vi algunos ejemplos en los que las personas crean una interfaz de repositorio (es decir IExampleRepository) y luego crean el repositorio real ( public class ExampleRepository : IExampleRepository) y un repositorio que se utilizará para las pruebas unitarias ( FakeExampleRepository : IExampleRepository).

En el IExampleRepositoryestaban implementando los mismos métodos que en el ExampleRepository, sin embargo, con diferentes consultas Linq.

¿Cuál es exactamente el objetivo aquí? ¿Pensé que una parte de la unidad que prueba su código es asegurarse de que un método funcione correctamente? Pero cuando uso dos consultas totalmente diferentes, una para 'real' y otra en la prueba, ¿qué sentido tiene la prueba?

jao
fuente

Respuestas:

8

Uno de los objetivos de las pruebas unitarias es probar solo una cosa a la vez, es decir, una sola clase y método. Si el repositorio en sí no está bajo prueba, normalmente se burlaría de esto de alguna manera para probar la lógica en su método / clase.

Dicho esto, también es necesario probar con un repositorio 'real' *, pero esto normalmente se haría en una prueba de integración / sistema

* obviamente real como en el repositorio configurado para la prueba, con suerte no, por ejemplo, el DB de producción.

jk.
fuente
Entonces, en las pruebas unitarias, ¿no probaré el método en sí para asegurarme de que devuelva los valores correctos (basados ​​en un conjunto de datos falsos / simulados)?
jao
sí, probará el método en sí mismo, pero solo el código del método, el código de otros objetos debería estar cubierto en otras pruebas unitarias, la interacción de varios objetos debería estar cubierta en pruebas de integración o pruebas de nivel superior
jk.
1
Ok, así que si entiendo correctamente, debería usar el repositorio original cuando la unidad pruebe los repositorios. No necesito probarlos cuando escribo pruebas unitarias para los Controladores (en el caso de Asp.Net MVC)
jao
44
@Theomax Depende del contexto: si estás probando un componente de software que no es tuyo ExampleRepository, entonces es mejor usar un simulacro. La justificación es que no está haciendo pruebas unitarias del repositorio sino algo más.
Andres F.
55
@Theomax Para expandir el comentario de AndresF .: Si está haciendo pruebas unitarias ExampleRepository, use la cosa real. Si está realizando pruebas unitarias RepositoryController, solo debe usar una FakeExampleRepositoryque devuelva valores especificados previamente. De esta manera, si un error aparece ExampleRepository, solo la prueba de la unidad fallará; RepositoryControllerlas pruebas continuarán teniendo éxito, por lo que sabe que no hay un error allí. Si el controlador usara el repositorio real, ambos estarían fallando y no sabría si tuvo 1 error o 2.
Izkata
5

Estoy de acuerdo con las dos respuestas de jk. y Jan Hudec, dan muy buena información. Pero pensé que agregaría un poco.

Su primera pregunta ("¿Cuál es exactamente el objetivo aquí?") Es importante. En el caso que está describiendo, el objetivo real es probar las clases que están utilizando la IExampleRepositoryinterfaz, no probar las implementaciones del repositorio. La creación de le FakeExampleRepositorypermite probar esas clases de clientes sin preocuparse por los detalles de la clase de repositorio real.

Esto es especialmente cierto si el objeto que está intentando configurar dificulta las pruebas (por ejemplo, accede al sistema de archivos, llama a un servicio web o habla con una base de datos). Mediante el uso de interfaces (y otras técnicas similares), mantiene el acoplamiento bajo. Por lo tanto, la clase Xsolo necesita saber acerca de la interfaz y no necesita conocer los detalles de implementación. El objetivo es asegurarse de que la clase Xesté haciendo lo correcto.

Burlarse (o tropezar, fingir ... hay diferencias matizadas) es una herramienta poderosa para pruebas unitarias y TDD. Pero puede ser complicado crear y mantener manualmente estas implementaciones. Por lo tanto, la mayoría de los idiomas ahora tienen bibliotecas falsas para ayudar. Como estás usando C #, recomendaría Moq porque es simple y muy poderoso. Luego puede probar con la interfaz sin acumular código adicional para las implementaciones simuladas.

Alano
fuente
the real objective is to test the classes that are utilizing the IExampleRepository interfaceEso no es estrictamente cierto. El objetivo es probarlo independientemente del IExampleRepository. +1 por recomendar un buen marco de aislamiento sin embargo.
StuperUser
1
Estoy en desacuerdo. No es independiente del IExampleRepositoryporque la clase bajo prueba está acoplada a esa interfaz. Pero es independiente de cualquier implementación de la interfaz. Sin embargo, admito que mi explicación probablemente podría usar un poco más de delicadeza. :)
Allan
5

¿Cuál es exactamente el objetivo aquí?

Aislamiento.

La idea de una unidad lo prueba para probar la unidad de código más pequeña posible . Para ello, aislarlo de todos los demás códigos de producción en la prueba.

Al crear clases falsas, el único código de producción es la clase bajo prueba.

Si crea un repositorio falso correctamente y la prueba falla, sabe que el problema está en el código bajo prueba. Esto le brinda el beneficio del diagnóstico de forma gratuita.

Eche un vistazo a los marcos de aislamiento (como Moq según lo sugerido por @Allan) para poder generar estas falsificaciones rápidamente para configurar las condiciones de prueba y utilizarlas para hacer valer.

StuperUser
fuente
Más detalles sobre falsificaciones, simulacros y trozos: stackoverflow.com/questions/346372/…
StuperUser
4

Hay tres razones por las que es posible que desee proporcionar una instancia simulada para la prueba unitaria:

  1. Desea limitar el alcance de la prueba, para que la prueba no se vea afectada por errores en el depósito, posiblemente porque aún no está terminada o no es estable o no desea que los errores de otra persona afecten sus pruebas.
  2. La dependencia es complicada de configurar. Por ejemplo, la capa de acceso a datos a menudo se burla, porque la verdadera requiere configurar una base de datos de prueba. Todavía necesita probar la capa de acceso a datos reales, pero puede limitar la configuración costosa al depurar otras cosas.
  3. Para probar que la clase dependiente reacciona correctamente a varios tipos de errores, proporciona una versión simulada que devuelve todo tipo de respuestas incorrectas. Porque muchos modos de falla son bastante difíciles de reproducir, pero aún deben ser probados.
Jan Hudec
fuente