2009-07-22 29 views
6

El producto actual en el que trabajo es un servicio de Windows escrito en C++ y en adelante todas las nuevas funcionalidades tendrán pruebas de unidad escritas para él. Pero esto crea un problema interesante (al menos para mí). Hacemos muchas llamadas a Win32 para varias cosas y nos comportamos en consecuencia, por lo tanto, para que las pruebas de la unidad estén completas, sería bueno probar una variedad de resultados, no solo el sistema actual. estado.Llamadas de API de Mocking y Win32

Mi pregunta es ¿cuál es la mejor manera de burlarse de los resultados de las llamadas de Win32? He pensado en dos métodos diferentes:

1) Poner todas las llamadas Win32 utilizadas en los punteros de función y pasarlas a las funciones o clases (dependiendo de cuántas veces se golpean) que las usen y usar esto para obtener simulacro resultados.

2) Tengo un montón de #ifdef UNITTEST en todas partes y si está llamando a mis propios métodos especiales o los llaman a los normales si no es así.

¿Estoy completamente fuera de base aquí, o me falta algo fundamental de conocimiento?

+1

¿Y si necesita argumentos con el fin de modificar el comportamiento de UnitTestMessageBox? #ifdef UNITTEST #undef MessageBox #define MessageBox UnitTestMessageBox #endif – Manolete

Respuesta

9

Con respecto a (2), la mayoría de las funciones de Win32 que toman los parámetros de cadena ya tienen su forma común definida como una macro, p. de winuser.h:

WINUSERAPI 
int 
WINAPI 
MessageBoxA(
    __in_opt HWND hWnd, 
    __in_opt LPCSTR lpText, 
    __in_opt LPCSTR lpCaption, 
    __in UINT uType); 
WINUSERAPI 
int 
WINAPI 
MessageBoxW(
    __in_opt HWND hWnd, 
    __in_opt LPCWSTR lpText, 
    __in_opt LPCWSTR lpCaption, 
    __in UINT uType); 
#ifdef UNICODE 
#define MessageBox MessageBoxW 
#else 
#define MessageBox MessageBoxA 
#endif // !UNICODE 

Por supuesto que podría agregar un encabezado a su proyecto que redefine las funciones de la API que desea simular:

#ifdef UNITTEST 
#undef MessageBox 
#define MessageBox UnitTestMessageBox 
#endif 

Al redefinir el nombre, puede evitar la dispersión de una gran cantidad de condicional compilación a través de su código fuente.

+0

Este fue mi pensamiento sobre cómo hacerlo. Evitaría cambiar sus firmas de funciones para realizar pruebas unitarias. –

-1

Cuando sea posible, sería mejor realizar los eventos sin modificar las llamadas de Win32.

Por ejemplo, en lugar de hacer su propio CreateFile que fallará porque un archivo está en uso, en su lugar abra exclusivamente el archivo con otro programa (que llame desde su unidad de prueba) luego ejecute la prueba unitaria.

Sin embargo, si debe burlarse de alguna llamada de win32, probablemente sería mejor crear una biblioteca contenedora alrededor de los conjuntos de llamadas de Win32 que desea realizar. Entonces no dañarás la alfabetización del código de la lógica principal.

2

Utilice Deviare API enganche e intercepte todas las llamadas de API y realice su prueba de unidad.

4

Recomendaría encapsular las llamadas a la API en interfaces bien factorizadas. Luego puede probar su lógica de negocio utilizando objetos simulados o dobles de prueba. No es necesario que pruebe la API de Windows en sí, porque esto ya lo hacen millones de aplicaciones de Windows que funcionan.

Una prueba de unidad nunca debe incluir acceso a hardware si no desarrolla hardware. Solo se trata de probar tu código lógico.

2

Al final tomé más un enfoque de C# -ish y creé interfaces que me permitían anular las llamadas de Win32 que quería usar.

Por ejemplo, yo tenía uno llamado IRegistryOperations que contenía RegOpenKey, RegQueryValueEx, RegNotifyChange y varios otros que estaba usando. Una predeterminada que simplemente llama a la función real se creó en el constructor, pero también tuve un constructor que tomó la interfaz para poder simular valores dudosos, etc.

(no estoy seguro si es de mala educación para responder a mi propia pregunta, sin embargo)

Cuestiones relacionadas