Pregunta

El verano pasado estuve desarrollando una aplicación CRUD básica de ASP.NET/SQL Server y las pruebas unitarias eran uno de los requisitos.Tuve algunos problemas cuando intenté realizar pruebas con la base de datos.Según tengo entendido, las pruebas unitarias deberían ser:

  • apátrida
  • independientes unos de otros
  • repetible con los mismos resultados, es decirsin cambios persistentes

Estos requisitos parecen estar en desacuerdo entre sí cuando se desarrolla una base de datos.Por ejemplo, no puedo probar Insert() sin asegurarme de que las filas a insertar aún no estén allí, por lo que primero debo llamar a Delete().Pero, ¿y si aún no están allí?Entonces necesitaría llamar primero a la función Exists().

Mi solución final involucró funciones de configuración muy grandes (¡qué asco!) y un caso de prueba vacío que se ejecutaría primero e indicaría que la configuración se ejecutó sin problemas.Se trata de sacrificar la independencia de las pruebas manteniendo su apatridia.

Otra solución que encontré es envolver las llamadas a funciones en una transacción que se puede revertir fácilmente, como XtUnit de Roy Osherove.Esto funciona, pero involucra otra biblioteca, otra dependencia, y parece una solución demasiado pesada para el problema en cuestión.

Entonces, ¿qué ha hecho la comunidad SO ante esta situación?


tgmdbm dijo:

Por lo general, usa su marco de prueba unitario automatizado favorito para realizar pruebas de integración, por lo que algunas personas se confunden, pero no siguen las mismas reglas.Se le permite involucrar la implementación concreta de muchas de sus clases (porque han sido probados en unidades).estas probando cómo sus clases concretas interactúan entre sí y con la base de datos.

Entonces, si leo esto correctamente, realmente no hay manera de efectivamente realizar una prueba unitaria de una capa de acceso a datos.¿O una "prueba unitaria" de una capa de acceso a datos implicaría probar, por ejemplo, los comandos/SQL generados por las clases, independientemente de la interacción real con la base de datos?

¿Fue útil?

Solución

No existe una forma real de realizar una prueba unitaria de una base de datos que no sea afirmar que las tablas existen, contienen las columnas esperadas y tienen las restricciones adecuadas.Pero normalmente no vale la pena hacerlo.

Normalmente no lo haces unidad probar la base de datos.Generalmente involucras la base de datos en integración pruebas.

Por lo general, utiliza su marco de prueba unitario automatizado favorito para realizar pruebas de integración, razón por la cual algunas personas se confunden, pero no siguen las mismas reglas.Se le permite involucrar la implementación concreta de muchas de sus clases (porque han sido probadas unitariamente).Estás probando cómo interactúan tus clases concretas entre sí y con la base de datos.

Otros consejos

Unidad DB

Puede utilizar esta herramienta para exportar el estado de una base de datos en un momento dado y luego, cuando realice pruebas unitarias, puede volver a su estado anterior automáticamente al comienzo de las pruebas.Lo usamos con bastante frecuencia donde trabajo.

La solución habitual a las dependencias externas en las pruebas unitarias es utilizar objetos simulados, es decir, bibliotecas que imitan el comportamiento de las reales con las que se están realizando las pruebas.Esto no siempre es sencillo y a veces requiere algo de ingenio, pero existen varias buenas bibliotecas simuladas (gratuitas) para .Net si no quieres "hacer las tuyas propias".Inmediatamente me vienen a la mente dos:

Simulacros de rinoceronte es uno que tiene bastante buena reputación.

NMock es otro.

También hay muchas bibliotecas simuladas comerciales disponibles.Parte de escribir buenas pruebas unitarias es en realidad diseñar el código para ellas; por ejemplo, utilizando interfaces donde tenga sentido, de modo que pueda "burlarse" de un objeto dependiente implementando una versión "falsa" de su interfaz que, sin embargo, se comporta de una manera forma predecible, con fines de prueba.

En las simulaciones de bases de datos, esto significa "burlarse" de su propia capa de acceso a la base de datos con objetos que devuelven objetos de tabla, fila o conjunto de datos creados para que los traten sus pruebas unitarias.

Donde trabajo, normalmente creamos nuestras propias bibliotecas simuladas desde cero, pero eso no significa que tengas que hacerlo.

Sí, debes refactorizar tu código para acceder a los Repositorios y Servicios que acceden a la base de datos y luego puedes simular o eliminar esos objetos para que el objeto bajo prueba nunca toque la base de datos.¡Esto es mucho más rápido que almacenar el estado de la base de datos y restablecerla después de cada prueba!

te lo recomiendo mucho Cantidad mínima de pedido como tu marco burlón.He usado Rhino Mocks y NMock.Moq fue muy simple y resolvió todos los problemas que tenía con los otros frameworks.

Tuve la misma pregunta y llegué a las mismas conclusiones básicas que los demás que respondieron aquí:No se moleste en probar la capa de comunicación de base de datos real, pero si desea probar las funciones de su modelo (para asegurarse de que estén extrayendo datos correctamente, formateándolos correctamente, etc.), utilice algún tipo de fuente de datos ficticia y pruebas de configuración. para verificar los datos que se están recuperando.

Yo también encuentro que la definición básica de pruebas unitarias no se adapta bien a muchas actividades de desarrollo web.Pero esta página describe algunos modelos de pruebas unitarias más "avanzados" y puede ayudar a inspirar algunas ideas para aplicar pruebas unitarias en diversas situaciones:

Patrones de prueba unitaria

Le expliqué una técnica que he estado usando para esta misma situación. aquí.

La idea básica es ejercitar cada método en su DAL (afirmar sus resultados) y cuando se complete cada prueba, revertir para que su base de datos esté limpia (sin datos basura/de prueba).

El único problema que quizás no le parezca "excelente" es que normalmente hago una prueba CRUD completa (no puramente desde la perspectiva de las pruebas unitarias), pero esta prueba de integración le permite ver su código de mapeo CRUD + en acción.De esta manera, si se rompe, lo sabrás antes de iniciar la aplicación (me ahorra un montón de trabajo cuando intento ir rápido)

Lo que debes hacer es ejecutar tus pruebas desde una copia en blanco de la base de datos que generas a partir de un script.Puede ejecutar sus pruebas y luego analizar los datos para asegurarse de que tengan exactamente lo que deberían después de ejecutar las pruebas.Luego simplemente eliminas la base de datos, ya que es desechable.Todo esto puede automatizarse y puede considerarse una acción atómica.

Probar la capa de datos y la base de datos juntas deja pocas sorpresas para más adelante en el proyecto.Pero las pruebas contra la base de datos tienen sus problemas, el principal es que está probando contra el estado compartido por muchas pruebas.Si inserta una línea en la base de datos en una prueba, la siguiente prueba también puede ver esa línea.
Lo que necesita es una forma de revertir los cambios que realiza en la base de datos.
El Alcance de la transacción La clase es lo suficientemente inteligente como para manejar transacciones muy complicadas, así como transacciones anidadas donde su código bajo las llamadas de prueba se compromete en su propia transacción local.Aquí hay un código simple que muestra lo fácil que es agregar capacidad de reversión a sus pruebas:

    [TestFixture]
    public class TrannsactionScopeTests
    {
        private TransactionScope trans = null;

        [SetUp]
        public void SetUp()
        {
            trans = new TransactionScope(TransactionScopeOption.Required);
        }

        [TearDown]
        public void TearDown()
        {
            trans.Dispose();
        }

        [Test]
        public void TestServicedSameTransaction()
        {
            MySimpleClass c = new MySimpleClass();
            long id = c.InsertCategoryStandard("whatever");
            long id2 = c.InsertCategoryStandard("whatever");
            Console.WriteLine("Got id of " + id);
            Console.WriteLine("Got id of " + id2);
            Assert.AreNotEqual(id, id2);
        }
    }

Si está utilizando LINQ to SQL como ORM, puede generar la base de datos sobre la marcha (siempre que tenga suficiente acceso desde la cuenta utilizada para las pruebas unitarias).Ver http://www.aaron-powell.com/blog.aspx?id=1125

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top