如何在Node.js中模拟MySQL(没有ORM)?
我使用felixge的node-mysql
客户端来使用Node.js。 我没有使用ORM。
我正在testing誓言,并希望能够嘲笑我的数据库,可能使用Sinon。 由于我本身并没有真正的DAL(除了node-mysql
),我不太确定如何去做这件事。 我的模型大多是简单的CRUD,有很多getter。
任何想法如何做到这一点?
用sinon,你可以在整个模块上放置一个模拟或存根。 例如,假设mysql
模块有一个函数query
:
var mock; mock = sinon.mock(require('mysql')) mock.expects('query').with(queryString, queryParams).yields(null, rows);
queryString
, queryParams
是你期望的input。 rows
是你所期望的输出。
当你testing的类需要mysql并调用query
方法时,它将被sinon截获和validation。
在你的testing期望部分,你应该有:
mock.verify()
在你的拆卸中,你应该把mysql恢复到正常的function:
mock.restore()
把你的数据库抽象成它自己的使用mysql的类是个好主意。 然后,您可以将该类的实例传递给模型的构造函数,而不是使用require()来加载它。
通过这个设置,你可以在你的unit testing文件中传递一个模拟数据库实例到你的模型中。
这是一个小例子:
// 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});
我并不完全熟悉node.js,但是从传统编程的angular度来看,要实现这样的testing,需要从数据访问方法中抽象出来。 难道你不能创build一个DAL类:
var DataContainer = function () { } DataContainer.prototype.getAllBooks = function() { // call mysql api select methods and return results... }
现在在testing的上下文中,在初始化期间修补你的getAllBooks类,如:
DataContainer.prototype.getAllBooks = function() { // Here is where you'd return your mock data in whatever format is expected. return []; }
当testing代码被调用时,getAllBooks将被replace为返回模拟数据而不是实际调用mysql的版本。 再次,这是一个粗略的概述,因为我不完全熟悉node.js
你可以使用horaa来模拟外部的依赖关系
而且我也相信felixge的节点沙盒模块也可以做类似的事情。
因此,使用kgilpin的相同的上下文,在horaa它看起来像这样:
var mock = horaa('mysql'); mock.hijack('query', function(queryString, queryParam) { // do your fake db query (eg, return fake expected data) }); //SUT calls and asserts mock.restore('query');
我最终以@kgilpin的答案开始,最后用类似的方法来testingAWS Lambda中的Mysql:
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'); }); }); }); });
我不想要任何实际的数据库连接,所以我手动嘲笑所有的MySQL响应。
通过添加另一个函数.returns
您可以嘲笑createConnection
任何方法。