2010-04-09 24 views
5

Supongamos que tengo una clase de C++, así:C++ y la inyección de dependencias en las pruebas unitarias

class A 
{ 
    public: 
     A() 
     { 

     } 

     void SetNewB(const B& _b) { m_B = _b; } 

    private: 
     B m_B; 
} 

Con el fin de probar la unidad algo así, tendría que romper la dependencia de A en B. Puesto que la clase A se aferra un objeto real y no un puntero, tendría que refactorizar este código para tomar un puntero. Además, necesitaría crear una clase de interfaz padre para B, así puedo pasar mi propia falsificación de B cuando pruebo SetNewB.

En este caso, no realiza pruebas con unidad de inyección de dependencias complicar aún más el código existente? Si hago de B un puntero, ahora estoy introduciendo la asignación de heap, y ahora parte del código es responsable de limpiarlo (a menos que use punteros refominados). Además, si B es una clase bastante trivial con solo un par de variables y funciones miembro, ¿por qué introducir una interfaz completamente nueva en lugar de simplemente probar con una instancia de B?

supongo que se podría hacer el argumento de que sería más fácil refactorizar Un mediante el uso de una interfaz. ¿Pero hay algunos casos en que dos clases pueden necesitar estar estrechamente vinculadas?

Respuesta

8

creo que está tomando la idea de las pruebas unitarias demasiado lejos. En este caso, A y B son una unidad, es decir, A no puede existir sin B. Primero, prueba B y asegúrate de que pase todas las pruebas unitarias específicas de B, luego una vez que pasa, prueba A y asegúrate de que comportarse como se supone que debe hacerlo.

+0

interesante, supongo que estaba imaginando que las pruebas unitarias requeridas todas las clases para ser completamente desacoplados entre sí. Pero como usted señala, A necesita absolutamente B para funcionar; entonces ellos son en realidad una unidad. – lhumongous

0

Dependiendo de cómo se utilice B, usted puede ser capaz de utilizar un std :: auto_ptr en lugar de un puntero ref-contados. Siempre que no necesite pasar una referencia a B a otra cosa que funcione y requiera cambios mínimos de código.

2

Si B es realmente una dependencia inyectada en A, entonces debe considerar una serie de otras opciones. En primer lugar está inyectando B en el momento de la construcción:

class A 
{ 
    public: 
     A(const B& _b) : m_B(_b) {} 

    private: 
     const B& m_B; 
}; 

Si realmente desea modificar B durante el ciclo de vida de su objeto A, a continuación, preguntarse si es realmente el dueño de B. De lo contrario, pase un puntero al mismo y suponga que el que lo pasa es responsable de su ciclo de vida; sin embargo, esta es una ruta complicada y puede requerir el uso de punteros ref-contados.

Si lo que quieres hacer es tomar una copia de B para ti, entonces podrías definir un método clone() en B. Si desea crear su propio objeto usando la información contenida en B entonces se puede inyectar un MyBFactory en el constructor y utilizarla con este B.