2009-04-24 18 views
20

Estoy escribiendo pruebas unitarias para una aplicación que usa una base de datos, y me gustaría poder ejecutar la aplicación con algunos datos de muestra/prueba, pero me ' No estoy seguro de la mejor manera de configurar los datos de prueba iniciales para las pruebas.Pruebas unitarias: Configuración de la base de datos para las pruebas

Lo que estoy buscando es un medio para ejecutar el código bajo prueba en la misma base de datos (o esquemáticamente idéntica) que utilizo actualmente durante la depuración, y antes de cada prueba, me gustaría asegurarme de que la base de datos se restablece a un borrón y cuenta nueva antes de insertar los datos de prueba.

Me doy cuenta de que el uso de un patrón IRepository me permitiría eliminar la complejidad de las pruebas en una base de datos real, pero no estoy seguro de que sea posible en mi caso.

¿Alguna sugerencia o artículo que pueda orientarme en la dirección correcta?

Gracias!

--EDIT--

Gracias a todos, esas son algunas sugerencias! Probablemente iré por la ruta de burlar mi capa de acceso a datos, combinada con algunas clases de configuración simples para generar exactamente los datos que necesito por prueba.

Respuesta

14

Aquí está el enfoque general que trato de usar. Concedo pruebas en aproximadamente tres o cuatro niveles: pruebas unitarias, pruebas de interacción, pruebas de integración, pruebas de aceptación.

En el nivel de prueba de la unidad, es solo código. Cualquier interacción con la base de datos es burlada, ya sea manualmente o usando uno de los frameworks populares, por lo que cargar datos no es un problema. Funcionan rápido y se aseguran de que los objetos funcionen como se esperaba. Esto permite ciclos de prueba de escritura/código de escritura/prueba muy rápidos. Los objetos simulados sirven los datos que necesita cada prueba.

Las pruebas de interacción prueban las interacciones de las interacciones de clases no triviales. De nuevo, no se requiere base de datos, se burla.

Ahora en el nivel de integración, estoy probando la integración de componentes, y ahí es donde entran en juego bases de datos, colas, servicios, yada yada. Si puedo, usaré uno de los populares en la memoria bases de datos, por lo que la inicialización no es un problema. Siempre comienza vacío, y utilizo las clases de utilidad para borrar la base de datos y cargar exactamente los datos que quiero antes de cada prueba, para que no haya un acoplamiento entre las pruebas.

El problema que he tenido al utilizar bases de datos en memoria es que a menudo no son compatibles con todas las funciones que necesito. Por ejemplo, tal vez requiera una combinación externa, y la base de datos en memoria no es compatible.En ese caso, generalmente probaré contra una base de datos convencional local como MySQL, de nuevo, restregándola antes de cada prueba. Dado que la aplicación se implementa en producción en un entorno separado, el ciclo de prueba no afecta a esos datos.

+0

¿Cómo son las clases de scrub? ¿Encuentra la ID de clave principal más reciente y elimina el registro asociado? –

+0

No, en realidad, elimina por completo todo y carga justo lo que necesito para la prueba. –

0

No creo que haya una manera fácil de terminar esto. Solo tiene que crear esos scripts de configuración sql de prueba previa y los scripts de eliminación de prueba posteriores a la prueba. Entonces necesita activar esos scripts para cada ejecución. Mucha gente sugiere SQLLite para la configuración de prueba de la unidad.

+1

SQLLite tiene muchas diferencias con las bases de datos grandes, por lo que no tiene sentido probarlo –

1

Sé que estás usando C#, pero en Java World está el marco Spring. Le permite ejecutar minipulaciones de la base de datos en una transacción y después de esta transacción, la recupera. Esto significa que opera contra una base de datos real sin tocar el estado una vez que finaliza la prueba. Tal vez esto podría ser una pista para una mayor investigación en C#.

+0

FYI - spring también está disponible para .net - http://www.springframework.net/ –

+1

¿Qué sucede si tengo que probar varias funciones de transacción? ¿Cómo sé que funcionan, si no puedo comprometerme? –

+0

Para dynmack.com: Sí, ese es el punto correcto, lamentablemente. – nightcoder

0

Encontré que lo mejor era que mis pruebas fueran a un DB diferente para poder limpiarlo y poner los datos que quería para la prueba.

Es posible que desee que la base de datos sea algo que pueda establecerse dentro del programa, entonces su prueba puede indicar a las clases que cambien la base de datos.

3

La mejor manera que he encontrado para manejar esto es utilizar una base de datos de prueba estática con datos conocidos, y usar transacciones para asegurar que sus pruebas no cambien nada.

En su configuración de prueba, usted iniciaría una transacción y, en la limpieza de prueba, reiniciaría la transacción. Esto le permite modificar los datos en sus pruebas, pero también se asegura de que todo vuelva a su estado original cuando finalice la prueba.

+0

¿Cómo sabes que tus cambios funcionaron si no comprometiste la transacción? –

+0

@Robert: después de realizar la actualización (pero antes de realizar la reversión), la prueba realizaría los controles necesarios para verificar que la actualización se realizó correctamente. Dado que las comprobaciones se ejecutan en la misma transacción que la actualización, deberían ver las actualizaciones aunque todavía no se hayan confirmado. –

+0

Para su idea, la transacción debe estar en prueba, no en el método que usted prueba. –

0

Este código borra todos los datos de las tablas de todos los usuarios de MS SQL Server:

private DateTime _timeout; 

public void ClearDatabase(SqlConnection connection) 
{ 
    _timeout = DateTime.Now + TimeSpan.FromSeconds(30); 
    do 
    { 
     SqlCommand command = connection.CreateCommand(); 
     command.CommandText = "exec sp_MSforeachtable 'DELETE FROM ?'"; 
     try 
     { 
      command.ExecuteNonQuery(); 
      return; 
     } 
     catch (SqlException) 
     { 
     } 
    } while (!TimeOut()); 

    if (TimeOut()) 
     Assert.Fail("Fail to clear DB"); 
} 

private bool TimeOut() 
{ 
    return DateTime.Now > _timeout; 
} 
+0

No es bueno, supongo. Tendría que ejecutarlos en el orden correcto; de lo contrario, las infracciones generarían excepciones –

1

que imita es la causa de la mejor manera a la unidad de probar el código.

En cuanto a las pruebas de integración, he tenido algunos problemas al usar bases de datos en memoria como SQLite, principalmente debido a pequeñas diferencias en el comportamiento y la sintaxis.

He estado utilizando una instancia local de MySql para pruebas de integración en varios proyectos. Un problema recurrente es la configuración del servidor y la creación de datos de prueba. He creado un pequeño paquete de Nuget llamado Mysql.Server (vea más en https://github.com/stumpdk/MySql.Server), que simplemente configura una instancia local de MySql cada vez que ejecuta sus pruebas.

Con esta instancia ejecutándose, puede configurar fácilmente estructuras de tablas y datos de muestra para sus pruebas sin preocuparse ni de su entorno de producción ni de la configuración del servidor local.

Cuestiones relacionadas