He descubierto que solo hay 3 formas de unidad de prueba (simulacro / stub) dependencias que son estáticas en C # .NET:
Dado que dos de estos no son gratuitos y uno no ha llegado a la versión 1.0, burlarse de cosas estáticas no es demasiado fácil.
¿Eso tiene métodos estáticos y tal "maldad" (en el sentido de prueba de unidad)? Y si es así, ¿por qué resharper quiere que haga algo que pueda ser estático, estático? (Suponiendo que resharper no sea también "malvado").
Aclaración: estoy hablando del escenario en el que desea probar un método por unidad y ese método llama a un método estático en una unidad / clase diferente . Según la mayoría de las definiciones de la unidad de pruebas, si usted acaba de dejar el método bajo prueba llame al método estático en la otra unidad / clase entonces estás no la unidad de pruebas, que son la integración de pruebas. (Útil, pero no una prueba unitaria).
fuente
Respuestas:
Mirando las otras respuestas aquí, creo que puede haber cierta confusión entre los métodos estáticos que mantienen el estado estático o causan efectos secundarios (lo que me parece una muy mala idea) y los métodos estáticos que simplemente devuelven un valor.
Los métodos estáticos que no tienen estado y no causan efectos secundarios deben ser fácilmente comprobables en la unidad. De hecho, considero que tales métodos son una forma de programación funcional de "pobre hombre"; le das al método un objeto o valor, y devuelve un objeto o valor. Nada mas. No veo cómo dichos métodos afectarían negativamente las pruebas unitarias en absoluto.
fuente
Parece que estás confundiendo datos estáticos y métodos estáticos . Resharper, si no recuerdo mal, recomienda hacer que los
private
métodos dentro de una clase sean estáticos si se pueden hacer, creo que esto produce un pequeño beneficio de rendimiento. ¡ No recomienda hacer "nada que pueda ser" estático!Los métodos estáticos no tienen nada de malo y son fáciles de probar (siempre que no cambien ningún dato estático). Por ejemplo, piense en una biblioteca de matemáticas, que es un buen candidato para una clase estática con métodos estáticos. Si tiene un método (artificial) como este:
entonces esto es eminentemente comprobable y no tiene efectos secundarios. Simplemente verifica que cuando pasas, digamos, 20 vuelves a 400. No hay problema.
fuente
System.Math
) sin mencionar la abundancia de métodos estáticos de fábrica, etc. Además, nunca podría usar ningún método de extensión, etc. El hecho es que funciones simples como esta son fundamental para los lenguajes modernos. Puede probarlos de forma aislada (ya que generalmente serán deterministas) y luego usarlos en sus clases sin preocuparse. No es un problema!Si la verdadera pregunta aquí es "¿Cómo pruebo este código?":
Luego, simplemente refactorice el código e inyecte como de costumbre la llamada a la clase estática de esta manera:
fuente
Las estadísticas no son necesariamente malas, pero pueden limitar sus opciones cuando se trata de pruebas unitarias con falsificaciones / simulacros / trozos.
Hay dos enfoques generales para burlarse.
El primero (tradicional, implementado por RhinoMocks, Moq, NMock2; también se utilizan simulacros y trozos manuales en este campo) se basa en las costuras de prueba y la inyección de dependencia. Supongamos que está probando un código estático y tiene dependencias. Lo que sucede a menudo en el código diseñado de esta manera es que las estadísticas crean sus propias dependencias, invirtiendo la inversión de dependencia . Pronto descubrirá que no puede inyectar interfaces simuladas en el código bajo prueba que está diseñado de esta manera.
El segundo (simulacros, implementado por TypeMock, JustMock y Moles) se basa en la API de creación de perfiles de .NET . Puede interceptar cualquiera de sus instrucciones CIL y reemplazar una porción de su código con una falsa. Esto permite que TypeMock y otros productos en este campamento se burlen de cualquier cosa: estática, clases selladas, métodos privados, cosas que no están diseñadas para ser comprobables.
Hay un debate en curso entre dos escuelas de pensamiento. Uno dice, siga los principios SÓLIDOS y el diseño para la comprobabilidad (que a menudo incluye ser fácil con las estadísticas). El otro dice, compre TypeMock y no se preocupe.
fuente
Mira esto: "Los métodos estáticos son la muerte para la testabilidad" . Breve resumen del argumento:
Para la prueba unitaria, debe tomar una pequeña parte de su código, volver a cablear sus dependencias y probarlo de forma aislada. Esto es difícil con los métodos estáticos, no solo en el caso de que accedan al estado global, sino incluso si solo llaman a otros métodos estáticos.
fuente
La verdad simple que rara vez se reconoce es que si una clase contiene una dependencia visible del compilador en otra clase, no se puede probar aisladamente de esa clase. Puede simular algo que parece una prueba y aparecerá en un informe como si fuera una prueba.
Pero no tendrá las propiedades definitorias clave de una prueba; fallando cuando las cosas están mal, pasando cuando están bien.
Esto se aplica a cualquier llamada estática, llamadas de constructor y cualquier referencia a métodos o campos no heredados de una clase o interfaz base . Si el nombre de la clase aparece en el código, es una dependencia visible para el compilador y no puede realizar una prueba válida sin él. Cualquier fragmento más pequeño simplemente no es una unidad comprobable válida . Cualquier intento de tratarlo como si tuviera resultados no será más significativo que escribir una pequeña utilidad para emitir el XML utilizado por su marco de prueba para decir 'prueba aprobada'.
Dado eso, hay tres opciones:
defina la prueba de unidad como prueba de la unidad compuesta por una clase y sus dependencias codificadas. Esto funciona, siempre que evite dependencias circulares.
nunca cree dependencias en tiempo de compilación entre clases que es responsable de probar. Esto funciona, siempre que no te importe el estilo de código resultante.
no prueba de unidad, prueba de integración en su lugar. Lo que funciona, siempre que no entre en conflicto con algo más para lo que necesite usar el término prueba de integración.
fuente
Math.Pi
Hacer referencia a un método no lo convierte en una prueba de integración por ninguna definición razonable.No hay dos formas de hacerlo. Las sugerencias de ReSharper y varias características útiles de C # no se usarían con tanta frecuencia si estuviera escribiendo pruebas de unidades atómicas aisladas para todo su código.
Por ejemplo, si tiene un método estático y necesita eliminarlo, no puede hacerlo a menos que use un marco de aislamiento basado en perfil. Una solución alternativa compatible con llamadas es cambiar la parte superior del método para usar la notación lambda. Por ejemplo:
ANTES DE:
DESPUÉS:
Los dos son compatibles con llamadas. Las personas que llaman no tienen que cambiar. El cuerpo de la función sigue siendo el mismo.
Luego, en su código de Prueba de unidad, puede anular esta llamada de esta manera (suponiendo que esté en una clase llamada Base de datos):
Tenga cuidado de reemplazarlo con el valor original una vez que haya terminado. Puede hacerlo mediante un intento / finalmente o, en la limpieza de la prueba de la unidad, la que se llama después de cada prueba, escriba un código como este:
que volverá a invocar el inicializador estático de su clase.
Las funciones Lambda no son tan ricas en soporte como los métodos estáticos regulares, por lo que este enfoque tiene los siguientes efectos secundarios indeseables:
Pero supongamos que evita las estáticas por completo, y convierte esto a un método de instancia. Todavía no se puede imitar a menos que el método sea virtual o esté implementado como parte de una interfaz.
Entonces, en realidad, cualquiera que sugiera el remedio para tropezar con métodos estáticos es hacerlos métodos de instancia, también estarían en contra de los métodos de instancia que no son virtuales o no son parte de una interfaz.
Entonces, ¿por qué C # tiene métodos estáticos? ¿Por qué permite métodos de instancia no virtuales?
Si utiliza cualquiera de estas "Características", simplemente no puede crear métodos aislados.
Entonces, ¿cuándo los usas?
Úselos para cualquier código que no espere que nadie quiera borrar. Algunos ejemplos: el método Format () de la clase String, el método WriteLine () de la clase Console, el método Cosh () de la clase Math
Y una cosa más ... A la mayoría de las personas no les importará esto, pero si puede hacerlo sobre el rendimiento de una llamada indirecta, esa es otra razón para evitar los métodos de instancia. Hay casos en que es un éxito de rendimiento. Es por eso que existen métodos no virtuales en primer lugar.
fuente
R # no es la única herramienta que hará esta sugerencia. El análisis de código de FxCop / MS también hará lo mismo.
En general, diría que si el método es estático, en general también debería ser comprobable. Eso trae un poco de consideración de diseño y probablemente más discusión de la que tengo en mis dedos en este momento, esperando pacientemente los votos y comentarios negativos ...;)
fuente
Veo que después de mucho tiempo, nadie ha declarado aún un hecho realmente simple. Si resharper me dice que puedo hacer que un método sea estático, significa algo enorme para mí, puedo escuchar su voz decirme: "hey, tú, estas piezas de lógica no son la RESPONSABILIDAD de manejar de la clase actual, por lo que deberían quedar fuera en alguna clase auxiliar o algo así ".
fuente
Si el método estático se llama desde otro método , no es posible evitar o sustituir dicha llamada. Esto significa que estos dos métodos forman una sola Unidad; La prueba de unidad de cualquier tipo los prueba a ambos.
Y si este método estático habla con Internet, conecta bases de datos, muestra ventanas emergentes de GUI o convierte la prueba de la Unidad en un desastre total, simplemente funciona sin ningún tipo de solución fácil. Un método que llama a este método estático no es comprobable sin refactorizar, incluso si tiene un montón de código puramente computacional que se beneficiaría enormemente de la prueba unitaria.
fuente
Creo que Resharper le brinda orientación y aplica las pautas de codificación con las que se ha configurado. Cuando he usado Resharper y me ha dicho que un método debe ser estático, seguramente estará en un método privado que no actúa en ninguna variable de instancia.
Ahora, en cuanto a la capacidad de prueba, este escenario no debería ser un problema, ya que no debería probar métodos privados de todos modos.
En cuanto a la capacidad de prueba de los métodos estáticos que son públicos, las pruebas unitarias se vuelven difíciles cuando los métodos estáticos tocan el estado estático. Personalmente, mantendría esto al mínimo y usaría métodos estáticos como funciones puras tanto como sea posible cuando se pasen las dependencias al método que se pueden controlar a través de un dispositivo de prueba. Sin embargo, esta es una decisión de diseño.
fuente