2011-07-15 9 views
6

¿Existe alguna razón por la cual no se deba crear una falsificación parcial de un objeto o simplemente simular un método en el objeto que se está probando con el fin de probar otro método? Esto podría ser útil para evitar que fabrique un nuevo objeto simulado completo, o cuando exista una dependencia externa en el método que está fingiendo del que no puede deshacerse razonablemente y que le gustaría mantener fuera de todas las otras pruebas unitarias.Fingir un método del objeto en prueba

+0

Disculpe, solo para aclarar: ¿tiene el objeto A en prueba, y el objeto A depende del objeto B, por lo que quiere crear una falsificación parcial del objeto B? –

+0

No, creando una falsificación parcial del objeto A. –

+0

Necesita [Powermock] (http://code.google.com/p/powermock/). Con esto puedes simular métodos estáticos, métodos privados, constructores, realmente puedes hacer magia porque modifica el bytecode de las clases. Esto es exactamente lo que necesitas. – edutesoy

Respuesta

1

El Extraer y Reemplazar técnica descrita en el capítulo 3 de Roy Osherove de El arte de la Unidad de Pruebas parece ser una forma de falsa parte de la clase bajo prueba (pp. 71-77). Osherove no aborda las preocupaciones planteadas en algunas de las otras respuestas a esta pregunta.

Además, Michael Feathers discute esto en Trabajando eficazmente con Legacy Code. Considera que la clase resultante es una subclase de prueba (227) y la técnica Subclase y método de sustitución (401). Ahora, concedido, Feathers no está dando una exposición de las técnicas prístinas que se recomiendan en el nuevo código. Pero todavía le da un tratamiento serio como una técnica potencialmente útil.

También le pregunté a mi antiguo profesor de informática sobre esto. Él es bien leído y actualmente trabaja a tiempo completo en la industria del software, donde ha avanzado rápidamente. Dijo que esta técnica definitivamente tiene una buena aplicación, y que hay varias docenas de clases en la base de código en su compañía que están bajo prueba de esta manera. Dijo que, como cualquier técnica, puede ser usada en exceso.

Originalmente escribí la pregunta cuando era nuevo en las pruebas unitarias y no sabía casi nada sobre la inyección de dependencia. Ahora, después de un poco de experiencia con ambos, agregaría que la necesidad de usar esta técnica de prueba podría ser un olor. Puede ser un signo de que es necesario volver a trabajar su enfoque a las dependencias. Si el método que debe ser falso es uno que se hereda de una clase base, puede significar que es necesario tomar más en serio el dicho "favorecer la composición sobre la herencia". Debe inyectar sus dependencias en lugar de heredarlas.

+0

[El capítulo 3 de Osherove está en línea] (http://www.manning.com/osherove/SampleChapter3.pdf) (PDF) –

3

Los objetos para los que desea hacer esto están intentando hacer demasiadas cosas. En particular, si tiene una dependencia externa, normalmente crearía un objeto para aislar esa dependencia. El patrón de Fachada es un ejemplo de esto. Si sus objetos no fueron diseñados con capacidad de prueba en mente, es posible que tenga que hacer algunas refactorizaciones. Eche un vistazo al Michael Feathers' PDF on working with legacy code (PDF). También tiene un libro del mismo título que entra en mucho más detalle.

+0

+1 - ¡es un gran libro! – TrueWill

0

Hay algunos paquetes realmente agradables para facilitar este tipo de cosas. Por ejemplo, desde el Mockito docs:

//You can mock concrete classes, not only interfaces 
LinkedList mockedList = mock(LinkedList.class); 

//stubbing 
when(mockedList.get(0)).thenReturn("first"); 

hace un poco de magia real que es difícil de creer al principio. Cuando llame al

String firstMember = mockedList.get(0); 

volverá "primero", por lo que dijo en la declaración "cuándo".

1

Si el método que quiere simular es virtual (como en, no estático y no es definitivo), puede subclasificar su objeto en la prueba, anular el método en la subclase y ejercitar la subclase en la prueba. No se requieren bibliotecas de objetos falsos.

(Lo ideal sería que usted debe considerar refactorización, esto no es una gran solución a largo plazo. Sin embargo, es una manera de conseguir el código heredado bajo prueba para que pueda comenzar el proceso de refactorización más fácilmente.)

2

Es una muy mala idea para burlarse/fingir parte de una clase para probar otra.

Haciendo esto, no está probando lo que hace el código real en las condiciones bajo prueba que conducen a resultados de prueba poco confiables.

También aumenta la carga de mantenimiento de la parte falsa de la clase. Si esto está en efecto para todo el programa de prueba, la implementación falsa también dificulta más otras pruebas del método falso.

Debe preguntarse por qué necesita falsificar la pieza bajo prueba.

Si es porque el método está accediendo a un archivo o base de datos, entonces debe definir una interfaz y pasar una instancia de esa interfaz al constructor o método de la clase. Esto le permite probar diferentes escenarios en la misma aplicación de prueba.

Si es porque está utilizando singletons, debe reconsiderar su diseño para que sea más comprobable: la eliminación de singletons eliminará las dependencias implícitas y las pesadillas de mantenimiento.

Si está utilizando métodos estáticos/funciones independientes para acceder a los datos de un registro o archivo de configuración, realmente debería quitarlo de la función bajo prueba y pasar los datos como un parámetro o proporcionar una interfaz de proveedor de configuraciones. Esto hará que el código sea más flexible y robusto.

Si se trata de romper una dependencia para fines de prueba (p.simulando un método vectorial para probar un método en una clase matricial), entonces no deberías fingir eso: debes tratar el código bajo prueba como lo define la clase bajo prueba por su interfaz pública: métodos; condiciones previas, condiciones posteriores, invariantes, documentación, parámetros y especificaciones de excepción.

Puede utilizar el conocimiento de los detalles de implementación para probar casos de borde especiales, pero desencadenarlos a través de la API principal, no falsificando un detalle de implementación.

Por ejemplo, supongamos que fingió std :: vector :: at() pero la implementación cambió para usar el operador [] en su lugar. Su prueba se romperá o pasará silenciosamente.

Cuestiones relacionadas