2011-12-05 17 views
34

Estoy usando Node.js con el cliente de felixge node-mysql. No estoy usando un ORM.¿Cómo se burla de MySQL (sin un ORM) en Node.js?

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

¿Alguna idea sobre cómo lograr esto?

+0

¿Me puede dar más detalles? Por ejemplo, pegue un código y muestre quizás un pseudocódigo de lo que le gustaría lograr. Me gustaría ayudar. – alessioalex

+0

@alessioalex Honestamente, ni siquiera sé por dónde empezar. Realmente, me gustaría ver la clase de modelo de otra persona y sus burlas/pruebas asociadas. –

Respuesta

22

Con sinon, se puede poner una maqueta o talón de alrededor de un módulo completo. Por ejemplo, supongamos que el módulo de mysql tiene una función query:

var mock; 

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

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

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

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

mock.verify() 

y en su desmontaje debe restaurar MySQL volver a funcionar normalmente:

mock.restore() 
+1

.with() parece haber quedado en desuso en favor de .withArgs(). Estoy probando con sinon 1.7.2 – AndreiM

+1

sería, por upvoted si ha dado un ejemplo completo. –

4

No estoy totalmente 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ía crear una clase DAL como:

var DataContainer = function() { 
} 

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

Ahora bien, en el contexto de una prueba, el parche de su 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 el código de prueba se llama, getAllBooks serán reemplazado por una versión que devuelve datos falsos en lugar de llamar a mysql. De nuevo, esta es una descripción aproximada ya que no estoy del todo familiar con node.js

7

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 falso 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}); 
3

Puede burlarse cabo dependencias externas usando horaa

Y también creo que el nodo de felixge sandboxed-module también puede hacer algo similar.

Así, utilizando un 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'); 
+0

sinon.js parece ser el defacto en estos días – dule

1

terminé a partir de la respuesta de @ kgilpin y terminó con algo como esto para probar MySQL en una EMA 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'); 
     }); 
    }); 
}); 
}); 

que no querían cualquier conexión de bases de datos reales, así que burlé manualmente todas las respuestas de MySQL.
Añadiendo otra función a .returns puede burlarse de cualquier método de createConnection.

Cuestiones relacionadas