我正在使用Node.js
与felixge的node-mysql
客户端。我没有使用ORM。
我正在测试Vows并希望能够模拟我的数据库,可能使用Sinon。由于我本身并没有真正的DAL(除了node-mysql
),我真的不确定如何解决这个问题。我的模型大多是简单的CRUD,有很多吸气剂。
关于如何实现这一目标的任何想法?
答案 0 :(得分:34)
使用sinon,你可以在整个模块周围放置模拟或存根。例如,假设mysql
模块具有函数query
:
var mock;
mock = sinon.mock(require('mysql'))
mock.expects('query').with(queryString, queryParams).yields(null, rows);
queryString
,queryParams
是您期望的输入。 rows
是您期望的输出。
当您的测试类现在需要mysql并调用query
方法时,它将被sinon拦截并验证。
在您的测试期望部分,您应该:
mock.verify()
在您的拆解中,您应该将mysql恢复为正常功能:
mock.restore()
答案 1 :(得分:9)
将数据库抽象为自己的使用mysql的类可能是个好主意。然后,您可以将该类的实例传递给模型的构造函数,而不是使用require()将它们加载。
通过此设置,您可以将模拟数据库实例传递给单元测试文件中的模型。
这是一个小例子:
// 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});
答案 2 :(得分:5)
我并不完全熟悉node.js,但在传统的编程意义上,要实现这样的测试,您需要从数据访问方法中抽象出来。你不能创建一个DAL类,如:
var DataContainer = function () {
}
DataContainer.prototype.getAllBooks = function() {
// call mysql api select methods and return results...
}
现在在测试环境中,在初始化期间修补你的getAllBooks类,如:
DataContainer.prototype.getAllBooks = function() {
// Here is where you'd return your mock data in whatever format is expected.
return [];
}
调用测试代码时,getAllBooks将替换为返回模拟数据的版本,而不是实际调用mysql。同样,这是一个粗略的概述,因为我并不完全熟悉node.js
答案 3 :(得分:5)
我最后以@ kgilpin的答案开始,最后用这样的东西来测试AWS 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
之外的任何方法。
答案 4 :(得分:3)
您可以使用horaa
模拟外部依赖项我也相信felixge的节点sandboxed-module也可以做类似的事情。
因此,使用kgilpin的相同上下文,在horaa中它看起来像:
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');