2012-09-21 21 views
59

¿Cómo puedo simular la base de datos en mi aplicación node.js, que en este caso usa mongodb como back-end para una API REST de blog?¿Base de datos burlona en node.js?

Claro, podría establecer la base de datos a una base de datos testing específica, pero aún así guardaría datos y no probaría solo mi código, sino también la base de datos, así que en realidad no estoy realizando pruebas unitarias sino de integración.
Entonces, ¿qué debería uno hacer? ¿Crear contenedores de base de datos como una capa intermedia entre la aplicación y db y reemplazar el DAL cuando se está probando?

// app.js 
var express = require('express'); 
    app = express(), 
    mongo = require('mongoskin'), 
    db = mongo.db('localhost:27017/test?auto_reconnect'); 

app.get('/posts/:slug', function(req, res){ 
    db.collection('posts').findOne({slug: req.params.slug}, function (err, post) { 
     res.send(JSON.stringify(post), 200); 
    }); 
}); 

app.listen(3000); 

// test.js 
r = require('requestah')(3000); 
describe("Does some testing", function() { 

    it("Fetches a blogpost by slug", function(done) { 
    r.get("/posts/aslug", function(res) { 
     expect(res.statusCode).to.equal(200); 
     expect(JSON.parse(res.body)["title"]).to.not.equal(null); 
     return done(); 
    }); 

    }); 
)); 

Respuesta

85

no creo código relacionado con la base de datos puede ser probado adecuadamente sin probarlo con el software de base de datos. Esto se debe a que el código que está probando no es solo javascript sino también la cadena de consulta de la base de datos. Aunque en su caso las consultas parecen simples, no puede confiar en que sea así para siempre.

Así que cualquier capa de emulación de base de datos necesariamente implementará toda la base de datos (menos el almacenamiento en disco). Para entonces terminas haciendo pruebas de integración con el emulador de base de datos, aunque lo llames prueba unitaria. Otro inconveniente es que el emulador de base de datos puede terminar teniendo un conjunto diferente de errores en comparación con la base de datos y puede que tengas que codificar tanto el emulador de base de datos como la base de datos (algo así como IE vs Firefox vs Chrome, etc.)

Por lo tanto, en mi opinión, la única manera de probar correctamente su código es relacionarlo con la base de datos real.

+1

Ya sabes, haces un buen punto. Si bien las pruebas unitarias tienen un propósito fenomenal (es decir, el aislamiento), ha constituido un punto fuerte para las pruebas de integración. –

+3

@MichaelPerrenoud: Me gusta la regla establecida por la respuesta de christkv: ** "No te burles de nada que no te pertenezca" **. Si bien no entra en detalles por qué es una mala idea, es una regla fácil de recordar. – slebetman

+1

No estoy de acuerdo con esta respuesta, en meteorjs configuraron una base de datos de prueba de alguna manera cuando se ejecutan pruebas (supongo que no es una biblioteca simulada, sino un archivo temporal) y es muy conveniente. Sería muy útil tener un objeto que se comporta exactamente como un mongodb y se limpia solo. Si está todo en la memoria o en un archivo temporal es el detalle de la implementación, por lo que no tiene que duplicar el código. Estoy de acuerdo en que las personas que fabrican el controlador deberían ser las que hacen el objeto simulado. – Uri

36

Hay una regla general cuando se trata de burla, que es

No te burles de cualquier cosa que no es dueño.

Si quiere burlarse del archivo db, escóndalo detrás de una capa de servicio abstraída y fingido esa capa. Luego, asegúrese de que la prueba de integración sea la capa de servicio real.

Personalmente, me he alejado de usar simulaciones para probarlas y las uso para el diseño de arriba abajo, ayudándome a impulsar el desarrollo desde la parte superior hacia la inferior burlándose de capas de servicio a medida que avanzo y luego implementando esas capas y escribiendo pruebas de integración . Utilizados como herramienta de prueba, tienden a hacer que su prueba sea muy frágil y en el peor de los casos conduce a una divergencia entre el comportamiento real y el comportamiento burlado.

+0

Claro que puedes esconderlo detrás de un repositorio o pasarela y usar el simulacro para conducir tu enfoque impulsado por la prueba y aislar tus pruebas unitarias ... ¿qué quieres decir con que no usas simulacros para probarlos entonces? Vas a mantener ese gateway/repositorio burlado aún en tus pruebas y de alguna forma usarás una interfaz para especificar la implementación real en tu repositorio a través de una interfaz ¿no? – PositiveGuy

3

Mi enfoque preferido para el código DB de prueba unitaria en cualquier idioma es acceder a Mongo a través de una abstracción de repositorio (aquí hay un ejemplo http://iainjmitchell.com/blog/?p=884). Las implementaciones variarán en términos de la funcionalidad específica de DB expuesta, pero al eliminar todo el código de Mongo de su propia lógica, estará en posición de probar la unidad. Simplemente reemplace la implementación de Mongo Repository con una versión apagada que es trivialmente fácil. Por ejemplo, solo almacene objetos en una simple colección de diccionarios en la memoria.

Obtendrá los beneficios de probar su propio código de esta manera sin dependencias de DB pero aún tendrá que realizar pruebas de integración con la base de datos principal porque probablemente nunca podrá emular las idiosincrasias de la realidad base de datos como otros han dicho aquí. El tipo de cosas que he encontrado son tan simples como la indexación en modo seguro vs sin modo seguro. Específicamente, si tiene un índice único, su implementación de la memoria ficticia podría cumplirlo en todos los casos, pero Mongo no lo hará sin el modo seguro.

Por lo tanto, aunque todavía tendrá que probar con la base de datos para algunas operaciones, sin duda podrá probar su propia lógica de manera adecuada con una implementación de repositorio anulada.

+0

pero en algún momento su código de implementación real tiene que hacer referencia a las llamadas de datos reales. Supongo que está inyectando la interfaz en su repositorio al código de consulta de la capa de datos real. – PositiveGuy

+0

Intente usar Docker. He solucionado años de problemas de configuración de pesadilla con bases de datos e instalaciones de paquetes mediante el uso de Docker para ejecutar contenedores que ejecutan bases de datos inicializadas con datos de prueba específicos para el escenario. De hecho, ejecuto pilas de 3 contenedores: uno con el DB, uno con el código de la aplicación y el otro con el controlador de prueba. Si su conjunto de datos es de tamaño moderado, puede incluso girar instancias paralelas de estas pilas, acortando considerablemente su ciclo de prueba. – Raidex

32

No estoy de acuerdo con la respuesta seleccionada o las otras respuestas hasta ahora.

¿No sería asombroso si pudiera detectar los errores generados por los cambios caóticos y muchas veces desordenados realizados a los esquemas DB y su código ANTES de llegar a QA? Apuesto a que la mayoría gritaría ¡diablos, sí!

Lo más seguro es que pueda y deba aislar y probar sus esquemas DB. Y no lo haces basado en un emulador o imagen pesada o recreación de tu DB y máquina. Esto es qué cosas como SQLite es solo como un ejemplo. Se burla basándose en una instancia liviana de memoria en ejecución y con datos estáticos que no cambian en esa instancia de memoria, lo que significa que realmente está probando su base de datos aisladamente y puede confiar en sus pruebas también. Y, obviamente, es rápido porque está en la memoria, es un esqueleto y se desecha al final de una prueba.

Así que sí debe y debe probar el SCHEMA que se exporta a una instancia de memoria muy ligera en cualquier motor de DB/tiempo de ejecución que esté utilizando, y que junto con agregar una cantidad muy pequeña de datos estáticos se convierte en su burla aislada DB.

Exporte sus esquemas reales de su base de datos real periódicamente (de forma automatizada) e importe/actualice esos en su memoria en la instancia de DB de memoria antes de cada pulsación en el control de calidad y sabrá instantáneamente si los últimos cambios DB realizados por su Los administradores de DB u otros desarrolladores que han cambiado el esquema últimamente han roto alguna prueba.

Si bien aplaudo el esfuerzo para dar lo mejor de sí mismo, votaría negativamente la respuesta actual si pudiera, pero soy nuevo y aún no he adquirido la reputación suficiente como para permitir mi habilidad para hacerlo.

En cuanto a la persona que respondió con "no se burle de nada que no le pertenece". Creo que quiso decir "no pruebes nada que no te importe". ¡Pero SI te burlas de cosas que no te pertenecen! ¡Porque esas son las cosas que no se prueban y que deben aislarse!

¡Planeo compartir el CÓMO con usted y actualizaré esta publicación en un punto futuro en el tiempo con el código JS de ejemplo real!

Esto es lo que muchos equipos impulsados ​​por pruebas hacen todo el tiempo. Solo tienes que entender cómo.

+8

actualizaciones sobre cómo todavía? – ChickenWing24

+3

Me encantaría votar, pero no puedo si no mitiga la pregunta y proporciona una solución. Actualiza tu publicación cuando tengas oportunidad. – Shanimal

2

Tuve este dilema y elegí trabajar con una base de datos de prueba y limpiarla cada vez que comienza la prueba. (cómo dejarlo todo: https://stackoverflow.com/a/25639377/378594)

Con NPM, incluso puede hacer un script de prueba que crea el archivo db y lo limpia después.

+0

esto es realmente un enfoque agradable y recomendaría a cualquiera que haga una canalización de CI/CD seria para hacerlo. Con las herramientas de JavaScript de hoy podemos crear/eliminar bases de datos de prueba fácilmente antes y después de ejecutar las pruebas. Yo discutiría si este enfoque es adecuado durante el desarrollo (no desea dejar caer y crear su base de datos en cada cambio de código), pero hay otra solución para eso.Al menos resuelve el problema de tener que mantener integraciones de plugins separadas que simulan los datos y los pegan en su entorno de prueba. – Nicky

4

¿Qué ?! ¿Por qué simular algo entonces? El propósito de la burla es omitir la complejidad y el código propio de prueba de la unidad. Si quiere escribir pruebas e2e, entonces use db.

Escribiendo código para setup/desmontaje un DB de prueba para pruebas unitarias es una deuda técnica e increíblemente insatisfactoria.

Hay bibliotecas simulacros en NPM:

mongo - https://www.npmjs.com/package/mongomock

mangosta - https://www.npmjs.com/package/mockgoose

Si esos no la las características que necesita, entonces sí es posible que necesite usar la cosa real .

+1

lol "mockgoose" top 5 nombre de paquete de NPM más divertido imo –

+0

En mi humilde opinión, es mejor burlarse que simular - https://jsmockito.org/ –

Cuestiones relacionadas