如何使用 sinon 和 Mocha 模拟对 mysql 查询 nodeJS 的 Promisify 调用?
Posted
技术标签:
【中文标题】如何使用 sinon 和 Mocha 模拟对 mysql 查询 nodeJS 的 Promisify 调用?【英文标题】:How to mock promisify call on mysql query nodeJS using sinon and Mocha? 【发布时间】:2021-12-10 13:56:58 【问题描述】:这是我使用 mysql 的代码 -
import * as mysql from 'mysql';
import promisify from 'util';
const connectionParams:any =
/* set as environment variables */
host: host,
user: user,
password: password,
port: parseInt(port)
;
var connection:any;
const getRecords = async (inputValue: string) =>
//validate inputValue
const userIds: string[] = [];
logger.info("Creating mysql connection");
try
connection = mysql.createConnection(connectionParams);
const query = promisify(connection.query).bind(connection);
const queryResult = await query( sql: sqlQuery, timeout: 1000, values: value1, inputValue] );
if (queryResult)
queryResult.forEach((row) =>
userIds.push(row.userid);
);
catch (error)
logger.info(error);
// console.log(error);
throw new Error('Could not retrieve user IDs');
finally
connection.end();
return userIds;
;
这是我的测试 -
it('should return a list of records when right inputs are given', async() =>
sinon.stub(process, 'env').value(
'database': 'TESTDB'
);
let dummyArray = [ userid: 'xyz' ];
let createConnection =
connect: function(connectionParams: any)
return Promise.resolve()
,
query : sinon.stub().withArgs().callsFake(function (...args): Promise<Object>
const dummyArray = [ userid: 'xyz' ];
return new Promise(function(resolve)resolve(dummyArray));
),
end: function()
;
let mySqlStub =
createConnection: sinon.stub().returns(createConnection)
;
const dbops = proxyquire('../../lib/dbops', 'mysql': mySqlStub).default;
expect(await dbops.getUserIds('Delete')).to.deep.equal(['xyz']);
);
如何为查询编写假函数?
查询: sinon.stub().withArgs().callsFake(function (...args): 承诺 const dummyArray = [ userid: 'xyz' ]; return new Promise(function(resolve)resolve(dummyArray)); )
这对我不起作用。我怎样才能让它工作?我无法让存根函数解析并返回主函数中的预期值。查询只是挂起并在超时后引发错误。错误发生在存根中的“matchingfakes”方法中。
【问题讨论】:
【参考方案1】:proxyquire
用于对模块或包中的独立函数导出进行存根。由于mysql
是一个对象,您可以通过sinon.stub(obj, 'method')
存根其方法。你不需要使用 proxyquire
包。
即使你使用util.promisify
为NodeJS error-First 回调方法生成promise 版本(mysql.query(sql, callback)
,回调签名是function (error, results, ...args): void
)。你需要使用.callsFake()
为这个方法创建一个mock实现,并通过调用它的回调来触发promise版本。
而且,您应该在对环境变量进行存根后import
函数。因为当你导入./dbops
模块时,模块作用域内的代码会立即执行,此时环境变量没有被存根。
例如
dbops.ts
:
import mysql from 'mysql';
import promisify from 'util';
const connectionParams: any =
host: process.env.HOST,
user: process.env.USER,
password: process.env.PASSWORD,
port: parseInt(process.env.PORT || '3306'),
;
var connection: any;
const getRecords = async (inputValue: string) =>
const sqlQuery = 'SELECT * FROM tests';
const value1 = '';
const userIds: string[] = [];
console.info('Creating mysql connection');
try
connection = mysql.createConnection(connectionParams);
const query = promisify(connection.query).bind(connection);
const queryResult = await query( sql: sqlQuery, timeout: 1000, values: value1, inputValue );
if (queryResult)
queryResult.forEach((row) =>
userIds.push(row.userid);
);
catch (error)
console.info(error);
throw new Error('Could not retrieve user IDs');
finally
connection.end();
return userIds;
;
export getRecords ;
dbops.test.ts
:
import sinon from 'sinon';
import mysql from 'mysql';
describe('69702002', () =>
it('should return a list of records when right inputs are given', async () =>
sinon.stub(process, 'env').value(
HOST: '127.0.0.1',
USER: 'testuser',
PASSWORD: 'testpwd',
PORT: '3306',
);
const getRecords = await import('./dbops');
const dummyArray = [ userid: 'xyz' ];
let connectionStub =
query: sinon.stub().callsFake((sql, callback) =>
callback(null, dummyArray);
),
end: sinon.stub(),
;
sinon.stub(mysql, 'createConnection').returns(connectionStub);
const actual = await getRecords('test input');
sinon.assert.match(actual, ['xyz']);
sinon.assert.calledWithExactly(mysql.createConnection,
host: '127.0.0.1',
user: 'testuser',
password: 'testpwd',
port: 3306,
);
sinon.assert.calledOnce(connectionStub.end);
);
);
测试结果:
69702002
Creating mysql connection
✓ should return a list of records when right inputs are given (945ms)
1 passing (952ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 90.48 | 50 | 100 | 90 |
dbops.ts | 90.48 | 50 | 100 | 90 | 27-28
----------|---------|----------|---------|---------|-------------------
【讨论】:
感谢您的回复。由于工作原因没有立即回复,我深表歉意。我尝试了上述解决方案并进行了小修复。如果方法 getRecords 不是默认导出,它会起作用。就我而言,我必须将其设为默认导出。我尝试调整,但它对我不起作用。但是,如果导出不是默认的,这是一个可行的解决方案。由于项目限制,我不得不使用 mysql 无服务器库,为此我能够像为 AWS RDS 建议的解决方案一样进行存根。以上是关于如何使用 sinon 和 Mocha 模拟对 mysql 查询 nodeJS 的 Promisify 调用?的主要内容,如果未能解决你的问题,请参考以下文章
使用javascript与Mocha和Sinon进行单元测试问题