una que propiedades programacion polimorfico herencia crear como clase atributos agregar c# unit-testing mocking nsubstitute

propiedades - que es override en c#



¿Se recomienda simular una clase concreta? (4)

En teoría, no hay ningún problema en burlarse de una clase concreta; estamos probando contra una interfaz lógica (en lugar de una interface palabra clave), y no importa si esa interfaz lógica es proporcionada por una class o interface .

En la práctica .NET / C # hace esto un poco problemático. Como mencionaste un framework de burla de .NET, asumiré que estás restringido a eso.

En .NET / C # los miembros no son virtuales por defecto, por lo que cualquier método basado en proxy de comportamiento burlón (es decir, deriva de la clase y reemplaza a todos los miembros para hacer cosas específicas de prueba) no funcionará a menos que marques explícitamente a los miembros como virtual . Esto genera un problema: está utilizando una instancia de una clase simulada que debe ser completamente segura en su prueba de unidad (es decir, no ejecutará ningún código real), pero a menos que se haya asegurado de que todo sea virtual , puede terminar con una combinación de ejecución de código real y falsa (esto puede ser especialmente problemático si hay lógica de constructor, que siempre se ejecuta, y se complica si hay otras dependencias concretas que se deben renovar).

Hay algunas formas de evitar esto.

  • Usa interfaces . Esto funciona y es lo que aconsejamos en la documentación NSubstitute , pero tiene la desventaja de potencialmente hinchar su base de código con interfaces que pueden no ser realmente necesarias. Podría decirse que si encontramos buenas abstracciones en nuestro código, naturalmente terminaremos con interfaces ordenadas y reutilizables que podemos probar. No lo he visto funcionar así, pero sí YMMV. :)
  • Diligentemente andar haciendo que todo sea virtual. Una desventaja discutible de esto es que estamos sugiriendo que todos estos miembros están destinados a ser puntos de extensión en nuestro diseño, cuando realmente solo queremos cambiar el comportamiento de toda la clase para las pruebas. Tampoco detiene la ejecución de la lógica del constructor, ni ayuda si la clase concreta requiere otras dependencias.
  • Utilice la reescritura de ensamblaje a través de algo como el complemento Virtuosity para Fody , que puede usar para modificar todos los miembros de la clase en su ensamblaje para que sea virtual.
  • Utilice una biblioteca burlona no basada en proxy como TypeMock (pagado) , JustMock (pagado) , Microsoft Fakes (requiere VS Ultimate / Enterprise, aunque su antecesor, Microsoft Moles , es gratis) o Prig (gratis + código abierto) . Creo que estos pueden burlarse de todos los aspectos de las clases, así como de los miembros estáticos.

Una queja común presentada contra la última idea es que usted está probando a través de una costura "falsa"; estamos yendo fuera de los mecanismos normalmente utilizados para extender el código para cambiar el comportamiento de nuestro código. Necesitar salir de estos mecanismos podría indicar rigidez en nuestro diseño. Entiendo este argumento, pero he visto casos en los que el ruido de crear otra interfaz supera los beneficios. Supongo que se trata de estar al tanto del posible problema del diseño; Si no necesita los comentarios de las pruebas para resaltar la rigidez del diseño, entonces son excelentes soluciones.

Una última idea que voy a tirar es jugar con cambiar el tamaño de las unidades en nuestras pruebas. Por lo general, tenemos una sola clase como unidad. Si tenemos varias clases cohesivas como nuestra unidad y tenemos interfaces que actúan como un límite bien definido alrededor de ese componente, entonces podemos evitar tener que simular tantas clases y en su lugar solo burlarnos de un límite más estable. Esto puede hacer que nuestras pruebas sean más complicadas, con la ventaja de que estamos probando una unidad cohesiva de funcionalidad y alentados a desarrollar interfaces sólidas alrededor de esa unidad.

Espero que esto ayude.

La mayoría de los ejemplos que se dan en el sitio web de framework de burlas es burlarse de Interface. Dejemos decir NSubstitute que estoy usando actualmente, todos sus ejemplos de burla es burlarse de la interfaz.

Pero, en realidad, vi a un desarrollador burlarse de una clase de concreto en su lugar. ¿Se recomienda simular una clase concreta?


La pregunta es más bien: ¿por qué no?

Puedo pensar en un par de escenarios donde esto es útil, como:

La implementación de una clase concreta aún no está completa, o el chico que lo hizo no es confiable. Entonces me burlo de la clase tal como está especificada y pruebo mi código.

También puede ser útil simular clases que hacen cosas como el acceso a la base de datos. Si no tiene una base de datos de prueba, es posible que desee devolver valores para sus pruebas que son siempre constantes (lo que es fácil burlándose de la clase).


No es que se lo recomiende, es que puedes hacer esto si no tienes otra opción.

Por lo general, un proyecto bien diseñado se basa en la definición de interfaces para sus componentes por separado, por lo que puede probar cada uno de ellos de forma aislada burlándose de los demás. Pero si está trabajando con un código / código heredado que no puede cambiar y aún desea probar sus clases, entonces no tiene otra opción y no puede criticarse por ello (suponiendo que haya hecho un esfuerzo para tratar de cambiar estos componentes a interfaces y se les negó el derecho a).


Actualización :

3 años después, quiero admitir que cambié de opinión.

Incluso en teoría, todavía no me gusta crear interfaces solo para facilitar la creación de objetos simulados, en la práctica (estoy usando NSubstitute) es mucho más fácil usar Substitute.For<MyInterface>() lugar de Substitute.For<MyInterface>() clases reales con múltiples parámetros, por ejemplo, Substitute.For<MyCLass>(mockedParam1, mockedParam2, mockedParam3) , donde cada parámetro se debe burlar por separado. Otros posibles problemas descritos en la documentación NSubstitute

En nuestra compañía, la práctica recomendada ahora es usar interfaces.

Respuesta original :

Si no tiene un requisito para crear múltiples implementaciones de la misma abstracción, no cree una interfaz. Tal como apuntaba David Tchepak , no desea hinchar su base de código con interfaces que pueden no ser realmente necesarias.

De http://blog.ploeh.dk/2010/12/02/InterfacesAreNotAbstractions.aspx

¿Extraes interfaces de tus clases para permitir el acoplamiento libre? Si es así, probablemente tenga una relación 1: 1 entre sus interfaces y las clases concretas que las implementan. Probablemente no sea una buena señal , y viola el Principio de abstracciones reutilizadas (RAP) .

Tener solo una implementación de una interfaz dada es un olor a código.

Si su objetivo es la capacidad de prueba , prefiero la segunda opción de la respuesta anterior de David Tchepak .

Sin embargo, no estoy convencido de que tengas que hacer que todo sea virtual. Es suficiente hacer virtuales solo los métodos, que va a sustituir. También agregaré un comentario al lado de la declaración del método de que el método es virtual solo para que sea sustituible por la prueba de burla de la unidad.

Sin embargo, tenga en cuenta que la sustitución de clases concretas en lugar de interfaces tiene algunas limitaciones. Ej. Para NSubstitute

Nota: los sustitutos recursivos no se crearán para las clases, ya que la creación y el uso de clases pueden tener efectos secundarios potencialmente no deseados

.