mysql node.js mocking vows sinon

¿Cómo se burla de MySQL(sin un ORM) en Node.js?



mocking vows (5)

Con sinon, puedes poner un simulacro o un trozo alrededor de un módulo completo. Por ejemplo, supongamos que el módulo mysql tiene una query función:

var mock; mock = sinon.mock(require(''mysql'')) mock.expects(''query'').with(queryString, queryParams).yields(null, rows);

queryString , queryParams es la entrada que espera. rows es el resultado que espera.

Cuando su clase bajo prueba ahora requiera mysql y llame al método de query , será interceptado y verificado por sinon.

En su sección de expectativa de prueba debe tener:

mock.verify()

y en su desmontaje debería restaurar mysql a la funcionalidad normal:

mock.restore()

Estoy usando Node.js con el cliente node-mysql felixge. No estoy usando un ORM.

Estoy probando Votos y quiero poder burlarme de mi base de datos, posiblemente usando Sinon. Como realmente no tengo un DAL per se (aparte de node-mysql ), no estoy realmente seguro de cómo hacerlo. Mis modelos son en su mayoría simples CRUD con muchos captadores.

¿Alguna idea sobre cómo lograr esto?


No estoy completamente familiarizado con node.js, pero en un sentido de programación tradicional, para lograr pruebas como esa, necesitaría abstraerse del método de acceso a datos. ¿No podrías crear una clase DAL como:

var DataContainer = function () { } DataContainer.prototype.getAllBooks = function() { // call mysql api select methods and return results... }

Ahora, en el contexto de una prueba, aplique parche a la clase getAllBooks durante la inicialización, como:

DataContainer.prototype.getAllBooks = function() { // Here is where you''d return your mock data in whatever format is expected. return []; }

Cuando se invoca el código de prueba, getAllBooks se reemplazará con una versión que devuelva datos falsos en lugar de llamar a mysql. De nuevo, esta es una descripción aproximada ya que no estoy completamente familiarizado con node.js


Puede burlarse de las dependencias externas usando horaa

Y también creo que el módulo sandboxed de nodo de felixge también puede hacer algo similar.

Entonces, usando el mismo contexto de kgilpin, en horaa se vería algo así como:

var mock = horaa(''mysql''); mock.hijack(''query'', function(queryString, queryParam) { // do your fake db query (e.g., return fake expected data) }); //SUT calls and asserts mock.restore(''query'');


Puede ser una buena idea abstraer su base de datos en su propia clase que usa mysql. Luego puede pasar la instancia de esa clase a los constructores de su modelo en lugar de cargarlo usando require ().

Con esta configuración, puede pasar una instancia de db simulada a sus modelos dentro de los archivos de prueba de su unidad.

Aquí hay un pequeño ejemplo:

// db.js var Db = function() { this.driver = require(''mysql''); }; Db.prototype.query = function(sql, callback) { this.driver... callback (err, results); } module.exports = Db; // someModel.js var SomeModel = function (params) { this.db = params.db } SomeModel.prototype.getSomeTable (params) { var sql = .... this.db.query (sql, function ( err, res ) {...} } module.exports = SomeModel; // in app.js var db = new (require(''./db.js''))(); var someModel = new SomeModel ({db:db}); var otherModel = new OtherModel ({db:db}) // in app.test.js var db = { query: function (sql, callback) { ... callback ({...}) } } var someModel = new SomeModel ({db:db});


Terminé comenzando con la respuesta de @kgilpin y terminé con algo así para probar Mysql en un AWS Lambda:

const sinon = require(''sinon''); const LambdaTester = require(''lambda-tester''); const myLambdaHandler = require( ''../../lambdas/myLambda'' ).handler; const mockMysql = sinon.mock(require(''mysql'')); const chai = require(''chai''); const expect = chai.expect; describe(''Database Write Requests'', function() { beforeEach(() => { mockMysql.expects(''createConnection'').returns({ connect: () => { console.log(''Succesfully connected''); }, query: (query, vars, callback) => { callback(null, succesfulDbInsert); }, end: () => { console.log(''Connection ended''); } }); }); after(() => { mockMysql.restore(); }); describe( ''A call to write to the Database with correct schema'', function() { it( ''results in a write success'', function() { return LambdaTester(myLambdaHandler) .event(anObject) .expectResult((result) => { expect(result).to.equal(succesfulDbInsert); }); }); }); describe( ''database errors'', function() { before(() => { mockMysql.expects(''createConnection'').returns({ connect: () => { console.log(''Succesfully connected''); }, query: (query, vars, callback) => { callback(''Database error!'', null); }, end: () => { console.log(''Connection ended''); } }); }); after(() => { mockMysql.restore(); }); it( ''results in a callback error response'', function() { return LambdaTester(myLambdaHandler) .event(anObject) .expectError((err) => { expect(err.message).to.equal(''Something went wrong''); }); }); }); });

No quería ninguna conexión de base de datos real, así que me burlé manualmente de todas las respuestas de MySQL.
Al agregar otra función a .returns , puede .returns cualquier método fuera de createConnection .