2012-04-23 14 views
8

digamos que usted tiene un sitio web, que utiliza una función para recuperar datos de la base de datos y devuelve el resultado que se mostrará/analizada/etc ...Cómo escribir pruebas unitarias para funciones que dependen de datos dinámicos?

Dado que los datos que se recupera de la base de datos es dinámico y podría potencialmente puede cambiar cada segundo del día, ¿cómo se escribe correctamente una prueba de unidad para esta función?

Digamos que se supone que la función devuelve una matriz de resultados. Obviamente, una prueba unitaria podría probar para ver si se devuelve una matriz o no. Pero, ¿qué sucede cuando los contenidos de la matriz son incorrectos debido a una consulta MySQL mal escrita? El tamaño de la matriz podría ser cero o el contenido de la matriz podría ser incorrecto. Ya que depende de datos en constante cambio, ¿cómo sabría la Prueba de Unidad lo que es correcto y lo que no? ¿Serían necesarias las llamadas a la base de datos dentro de la Prueba unitaria para que haya algo con lo que compararlo?

¿Cómo se escribe correctamente una Prueba de unidad para funciones que dependen de datos dinámicos?

+0

Esto podría ser interesante: http://blog.schauderhaft.de/2011/03/13/testing-databases-with-junit-and -hibernate-part-1-one-to-rule-them/ –

Respuesta

7

Las pruebas unitarias, en su forma ideal, solo deberían probar una cosa. En este caso, se está probando dos cosas:

  1. la lógica de la función
  2. la recuperación de la base de datos

así que yo sugeriría la siguiente refactor:

  1. Mover el lógica de recuperación de base de datos en una función separada
  2. Haga que la función que desea probar llame a esa otra función
  3. Falsee la función que devuelve datos para que pueda probar la unidad solo la lógica de su aplicación
  4. Si tiene sentido (si solo está confiando en otra biblioteca para hacer esto, entonces con suerte esa lib ya tiene pruebas), escriba una prueba unitaria para la función de recuperación dinámica, donde no puede probar detalles, pero puede probar la estructura y la razonabilidad de los datos devueltos (p. ej. tiene todos los campos establecidos, y es un tiempo dentro de los 5 segundos de ahora).

Además, por lo general es una buena idea ejecutar pruebas unitarias en un entorno de prueba donde tiene control total sobre lo que está almacenado en la base de datos. No desea ejecutar estos contra datos de producción.

+0

Buenos puntos. Entonces, ¿está diciendo que deberíamos probar solo la lógica de nuestras funciones de recuperación de datos, no si los datos recuperados son correctos o no? Además, en nuestro entorno de desarrollo, normalmente hacemos una sincronización en un solo sentido de nuestro DB en vivo -> dev DB para que trabajemos con datos recientes. En cualquier caso, los datos siguen siendo dinámicos. Gracias. –

+0

En el nivel de la unidad, tiendo a preferir probar que mi lógica para lo que escribo en el db es correcta, así como mi lógica para lo que hago con mis lecturas. No necesito probar la unidad sql en la base de datos, a menos que esté usando algún ORM personalizado que construí. Luego, normalmente escribiré pruebas funcionales o de integración que demuestren que mi información es la que espero que sea. Realice estos contra un db que no se actualiza por otra cosa que las pruebas. Simular escenarios del mundo real con datos dinámicos está bien para las pruebas de integración (y rendimiento), pero la confianza en el sistema debería ser de las otras. –

+0

¿Cómo se burla de una función? –

0

No puedes, realmente. Necesitará un conjunto estático de datos garantizados para crear pruebas unitarias confiables. Quizás una instantánea de base de datos funcione para usted.

datos dinámicos pueden ser útiles en otras formas, como por ejemplo para realizar pruebas de regresión ...

0

mayoría de las pruebas se centran en los caminos lógicos que están involucrados en cosas como la obtención de datos. No sobre la validez de los datos en sí. La validez de los datos solo es significativa si su aplicación de alguna manera está calculando o agregando o lo que sea, en cuyo caso debería poder controlar las entradas y verificar que los resultados sean correctos.

Dicho esto, a veces querrás acceder a la misma base de datos que tu aplicación para verificar las devoluciones. Por ejemplo, si está probando una función que devuelve un conjunto de datos filtrados, la prueba unitaria podría realizar la misma consulta y luego hacer una comparación fila por fila de, digamos, cada una de las claves primarias y verificar que su función devolvió el mismo conjunto de datos que estabas esperando

No sé si esta es su pregunta específica, pero no hay nada de malo en presionar la base de datos para realizar afirmaciones en pruebas unitarias, por el contrario. Al menos lo hago todo el tiempo y nadie ha intentado arrestarme :)

0

Ignorando el hecho de que usted está hablando de la base de datos Creo que usted puede estar buscando las pruebas de su unidad para cubrir cada eventualidad, ya que eso puede conducir a un conjunto de rendimientos decrecientes. Si fuera usted, cubriría un camino estándar y luego un par de casos extremos. El hecho es que no puedes probar pragmáticamente todo.

aquí hay algo de lectura adicional

http://37signals.com/svn/posts/3159-testing-like-the-tsa
How deep are your unit tests?
http://johnnosnose.blogspot.co.uk/2012/04/re-over-testing.html
http://martinfowler.com/bliki/TestCoverage.html

En cuanto a su problema relacionado db specifc, para probar esta función es probable que necesite para crear un seam de comprobar la validez poulate los datos para que pueda cubrir esos casos.

+0

Heh En mi experiencia, la mayoría de los errores se infiltran precisamente en las áreas que son difíciles de probar, y por lo tanto parece que esas son las únicas áreas que realmente se benefician de una inversión de tiempo en un marco de prueba. Los gerentes ven eso, estoy seguro, y piensan: "solo necesitamos más pruebas unitarias para x, y z" cuando de hecho "x", "y" y "z" están esencialmente definidos por la característica de ser casi no comprobables. Por estas razones, considero que las pruebas unitarias son apenas más flexibles que las prácticas OOP basadas en UML más rígidas y no ágiles. Como desarrollador individual que trabaja por hora, es realmente un trabajo para una bala de plata. –

1

Si su función hace algo interesante más allá de sacar los datos de la base de datos, debe extraer la recuperación en una función diferente y simularla, para que pueda probar el resto.

Esto todavía te deja con la tarea de probar el acceso a la base de datos. Realmente no se puede hacer una prueba unitaria para eso, porque eso por definición no tendría acceso a ningún archivo db y podría probar si envía el enunciado sql que cree que debería, pero no si el enunciado sql realmente funciona.

por lo que necesita una base de datos

Usted tiene varias optiones:

1) crear una base de datos fija para este tipo de pruebas que no puedan ser cambiados por las pruebas.

Pro: Conceptualmente fácil Con: difícil de mantener. Las pruebas se vuelven interdependientes porque dependen de los mismos datos. No hay forma de probar cosas que hagan actualizaciones, insertos o borrados (y mucho menos DDL)

2) crear una base de datos durante la prueba. Ahora tiene dos problemas: configurar la base de datos para la prueba y llenarla con datos.

Configuración:

1) tiene un servidor de base de datos en ejecución, con un usuario/esquema/base de datos para erveryone que necesita para ejecutar las pruebas (al menos desarrolladores + ci-servidor). Schema puede crearse usando cosas como Hibernate o los scripts que usa para la implementación.

Funciona muy bien, pero vuelve locos a los anticuados DBA. La aplicación no debe depender del nombre del esquema. También tendrá problemas cuando tenga más de un esquema utilizado por la aplicación. Esta configuración es bastante lenta. Puede ayudar a poner en discos rápidos. Al igual que los discos RAM

2) Tener una base de datos en la memoria. Fácil de comenzar desde el código y rápido. Pero en la mayoría de los casos se comportará igual que su base de datos de producción. Esto es menos preocupante si usa algo que intenta ocultar la diferencia. A menudo uso una base de datos en memoria para la primera etapa de compilación y otra real en una segunda etapa.

Carga del testdata

1) la gente me dice utilizar DBUnit. No estoy seguro de que parezca que hay muchos XML y es difícil de mantener cuando las columnas o restricciones cambian.

2) Prefiero el código de aplicación normal. (Java + Hibernate) en mi caso, pero el código que escribe sus datos en la base de datos en producción debería ser adecuado en muchos casos para escribir datos de prueba para su prueba. Ayuda tener una pequeña API especial que oculta los detalles de la satisfacción de todas las claves foráneas y cosas: http://blog.schauderhaft.de/2011/03/13/testing-databases-with-junit-and-hibernate-part-1-one-to-rule-them/

0

Construiría los datos en la prueba misma. De esta manera, incluso puede probar escenarios complicados para los datos cambiantes. El punto clave es que puede controlar los cambios de datos en sus pruebas con una prueba dedicada db,

Paso 1: inserte los datos que necesita en un db que solo se utiliza con la prueba Paso 2: El db es ahora en un estado predecible estable, para que pueda ejecutar sus consultas y probar la salida

Cuestiones relacionadas