2010-11-18 17 views
6

He estado leyendo que los métodos estáticos tienden a evitarse cuando se usa TDD porque tienden a ser difíciles de burlar. Sin embargo, creo que lo más fácil para la prueba unitaria es un método estático que tiene una funcionalidad simple. No tiene que crear instancias de ninguna clase, fomenta métodos que de una forma simple, una sola cosa, son "independientes", etc.métodos estáticos y pruebas unitarias

¿Puede alguien explicar esta discrepancia entre las mejores prácticas de TDD y la facilidad pragmática?

gracias, Un

Respuesta

14

Un método estático es fácil de probar, pero algo que llama directamente a un método estático en general, no es fácil de probar independiente del método estático que depende. Con un método no estático puedes usar una instancia stub/mock/fake para facilitar las pruebas, pero si el código que estás probando llama a métodos estáticos, está efectivamente "conectado" a ese método estático.

+0

Creo que el término que está buscando porque está estrechamente unido. –

+1

@Martin: Gracias, conozco el término, aunque es más general de lo que estaba viendo aquí. Los términos comúnmente usados ​​a menudo terminan por perder su significado porque las personas (ab) los usan tanto, así que elegí usar una metáfora aquí con la esperanza de que sería más claro. –

+0

Audición por primera vez "cableada" en lugar de estrechamente acoplada. Es absolutamente brillante cómo un cambio en los términos puede ayudar a la comprensión. – jrahhali

2

Es fácil probar el método estático. El problema es que no hay forma de aislar el otro código de ese método estático cuando se prueba el otro código. El código de llamada está estrechamente relacionado con el código estático.

Una referencia a un método estático no puede ser burlada por muchos marcos de burla ni puede ser anulada.

Si tiene una clase que realiza muchas llamadas estáticas, para probarla debe configurar el estado global de la aplicación para todas esas llamadas estáticas, por lo que el mantenimiento se convierte en una pesadilla. Y si tu prueba falla, entonces no sabes qué bit de código causó la falla.

Hacer esto mal, es una de las razones por las que muchos desarrolladores piensan que TDD no tiene sentido. Pusieron un gran esfuerzo de mantenimiento para los resultados de las pruebas que solo indican vagamente lo que salió mal. Si solo hubieran reducido el acoplamiento entre sus unidades de código, entonces el mantenimiento sería trivial y los resultados de la prueba serían específicos.

3

La respuesta a la pregunta es, en mi opinión, "Object Oriented parece ser todo lo que la gente de TDD piensa".

¿Por qué? No lo sé. Quizás todos son programadores de Java que han sido infectados con la enfermedad de hacer que todo dependa de seis capas de indirección, inyección de dependencia y adaptadores de interfaz.

Los programadores de Java parecen querer hacer que todo sea difícil por adelantado para "ahorrar tiempo después".

Aconsejo aplicar algunos principios Agile a su TDD: Si no está causando un problema, no lo solucione. No más de diseño.

En la práctica, me parece que si los métodos estáticos se prueban bien primero, entonces no van a ser la causa de errores en sus llamadores.

Si los métodos estáticos se ejecutan rápidamente, entonces no es necesario un simulacro.

Si los métodos estáticos funcionan con cosas externas al programa, entonces es posible que necesite un método simulado. En este caso, necesitaría poder simular muchos tipos diferentes de comportamiento de funciones.

Si necesita simular un método estático, recuerde que hay formas de hacerlo fuera de de programación OO.

Por ejemplo, puede escribir scripts para procesar su código fuente en un formulario de prueba que llame a su función de simulacro.Puede vincular diferentes archivos de objeto que tienen diferentes versiones de la función en los programas de prueba. Puede usar trucos de enlazadores para anular la definición de la función (si no se insertó). Estoy seguro de que hay algunos trucos más que no he enumerado aquí.

+0

Estoy de acuerdo con usted en los casos simples. Muchos métodos estáticos son simples llamadas de utilidad que son estáticas porque no tienen estado. Pero otras llamadas estáticas hacen referencia a variables globales (estáticas) u otras llamadas estáticas, y esto puede ser muy difícil de manejar en un entorno de pruebas unitarias. Debe asegurarse de que el estado global sea el correcto para cada ejecución de prueba; de lo contrario, tendrá defectos (pruebas que funcionan de forma aislada pero fallan cuando se ejecuta el resto del conjunto). Entonces puede ser una lata de gusanos, pero estoy de acuerdo en que debes ser pragmático al respecto. – sheikhjabootie

0

Ese consejo es cierto en su mayor parte ... pero no siempre. Mis comentarios no son C++ específica .. pruebas

  1. de escritura para los métodos estáticos (que son puro/sin estado funciones): es decir, el trabajo fuera de las entradas para producir un resultado coherente. p.ej. Añada abajo: siempre dará el mismo valor dado un conjunto particular de entradas. Hay sin problema al escribir pruebas para estos o código que llama a estos métodos estáticos puros.
  2. escribiendo pruebas para métodos estáticos que consumen el estado estático: p. GetAddCount() a continuación. Llamarlo en múltiples pruebas puede arrojar valores diferentes. Por lo tanto, una prueba puede dañar la ejecución de otra prueba: las pruebas deben ser independientes. Así que ahora tenemos que introducir un método para restablecer el estado estático de modo que cada prueba pueda comenzar desde cero (por ejemplo, algo así como ResetCount()).
  3. Escritura de pruebas para código que tiene acceso a métodos estáticos pero no hay acceso de código fuente a la dependencia: Una vez más, depende de las propiedades de los métodos estáticos. Sin embargo, si son retorcidos, tienes una dependencia difícil. Si la dependencia es un objeto, entonces puede agregar un setter al tipo dependiente y establecer/inyectar un objeto falso para sus pruebas. Cuando la dependencia es estática, es posible que necesite una refactorización considerable antes de poder realizar las pruebas de manera confiable. (Por ejemplo, añadir un medio-hombre dependencia de los objetos que los delegados al método estático. Plug-in de un medio-hombre falso para sus pruebas)

permite echar un ejemplo

public class MyStaticClass 
{ 
    static int __count = 0; 
    public static int GetAddCount() 
    { return ++__count; } 

    public static int Add(int operand1, int operand2) 
    { return operand1 + operand2; } 

    // needed for testability 
    internal static void ResetCount() 
    { 
    __count = 0; 
    } 
} 

... 

//test1 
MyStaticClass.Add(2,3);  // => 5 
MyStaticClass.GetAddCount(); // => 1 

// test2 
MyStaticClass.Add(2,3); // => 5 
//MyStaticClass.ResetCount(); // needed for tests 
MyStaticClass.GetAddCount(); // => unless Reset is done, it can differ from 1