我有一个带有以下设置的项目:JavaScript ES6(使用Babel编译),mocha测试,使用node-mysql和Bluebird Promises访问MySql。
也许将Bluebird与Babel / ES6一起使用已经是我的第一个问题,但让我们解释一下情况和问题:
我的DBRepository对象:
let XDate = require('xdate'),
_ = require('lodash');
const Promise = require("bluebird");
const debug = require('debug')('DBRepository');
class DBRepository {
constructor(mysqlMock) {
"use strict";
this.mysql = mysqlMock;
if( this.mysql == undefined) {
debug('init mysql');
this.mysql = require("mysql");
Promise.promisifyAll(this.mysql);
Promise.promisifyAll(require("mysql/lib/Connection").prototype);
Promise.promisifyAll(require("mysql/lib/Pool").prototype);
}
this.config = {
connectionLimit: 10,
driver: 'pdo_mysql',
host: 'my_sql_container',
port: 3306,
user: 'root',
password: '**********',
testDbName: 'db-name'
};
this.pool = this.mysql.createPool(this.config); // <== Here the error is thrown
}
getSqlConnection() {
return this.pool.getConnectionAsync().disposer(function (connection) {
try {
connection.release();
} catch (e) {
debug('Error on releasing MySQL connection: ' + e);
debug(e.stack);
}
});
}
getGoods(queryParams) {
"use strict";
if (queryParams === undefined) {
queryParams = {};
}
if (queryParams.rowCount === undefined) {
queryParams.rowCount = 15;
}
let query = "SELECT id, name FROM my_table";
return Promise.using(this.getSqlConnection(), (conn => {
debug('query: ' + query);
return conn.queryAsync(query);
}));
}
}
这段代码在我的普通代码中对我来说很好,但是当我尝试在mocha测试中使用int时,使用sinon进行模拟我得到以下错误TypeError: this.mysql.createPool is not a function
这是我的测试代码:
let expect = require('chai').expect,
XDate = require('xdate'),
_ = require('lodash'),
sinon = require('sinon'),
Promise = require('bluebird'),
toBeMocketMySql = require('mysql');
Promise.promisifyAll(toBeMocketMySql);
Promise.promisifyAll(require("mysql/lib/Connection").prototype);
Promise.promisifyAll(require("mysql/lib/Pool").prototype);
describe(".inflateOffers(offerPCs, offerGroups)", () => {
"use strict";
it('should inflate Offers (with all OfferGroups and a PricingCluster from db rows.', () => {
let offerPCs = JSON.parse('[... some objects ...]');
let offerGroups = JSON.parse('[... some objects ...]');
let mock = sinon.mock(toBeMocketMySql);
let dbRepo = new DBRepository(mock); // <== Here the error is thrown
let offers = dbRepo.inflateObjects(offerPCs, offerGroups);
expect(offers).to.be.an('object')
.and.to.be.an('array')
.to.have.length(1);
expect(offers[0]).to.be.an('object')
.and.not.to.be.an('array')
.to.have.property('a')
.to.have.property('b');
});
});
也许根本不可能嘲笑一个满意的对象?
有人在这方面有过这方面的经验吗?
答案 0 :(得分:2)
DBRepository
很难测试,因为有一点太多 - 为了使测试更容易,你需要分开一些问题。至少你需要将业务逻辑(原始SQL查询)分解为他们自己的类,如下所示:
class GoodsService {
/**
* Constructor - inject the database connection into the service.
*
* @param {object} db - A db connection
*/
constructor(db) {
this.db = db;
}
getGoods(queryParams) {
if (queryParams === undefined) {
queryParams = {};
}
if (queryParams.rowCount === undefined) {
queryParams.rowCount = 15;
}
let query = "SELECT id, name FROM my_table";
debug('query: ' + query);
return this.db.queryAsync(query);
}
}
现在,您已将业务逻辑与设置数据库连接器分开了。您可以将完全实例化的数据库连接或存根传递到服务类测试中,如下所示:
let assert = require('assert');
describe('GoodsService', () => {
it('should return an array', () => {
let stubbedDb = {
queryAsync: () => {
return Promise.resolve([]);
}
};
let instance = new GoodsService(stubbedDb);
return instance.getGoods()
.then((result) => {
assert(Array.isArray(result), 'should return an array of something');
});
});
});
这有点过于简单,但你应该明白这一点。但是有一些事情需要注意。
你不需要像Chai这样的花哨的东西来测试承诺。 Mocha已经为此提供了良好的内置支持。
你不需要像sinon.mock
那样使用魔法。相反,保持简单,只是&#34;存根&#34;您需要在依赖项中测试的方法。但是,您可以使用&#34;间谍&#34;检查是否正在生成正确的SQL,但我在集成测试中这样做。
这有帮助吗?