无法正确模拟承诺和回调



我正试图在js文件"eslModule.js"中测试以下方法,但没有成功


async function exec(cmd, args, ip, port) {
const connPromise = new Promise(function(resolve, reject) {
try {
sock = new esl.Connection(ip, port, 'pwd', function() {
sock.bgapi(command, function(result) {
if (sock && sock.socket.writable && sock.socket.readable) {
sock.disconnect();
}
return resolve({
result: result.body
});
});
});
} catch (error) {
return reject(error);
}
sock.on('error', function(error) {
if (sock === null) {
return false;
}
if (error.code === 'ERR1' || error.code === 'ERR2') {
error.message = `Connection failed: [${error.code}]`;
}
if (sock && sock.socket.writable && sock.socket.readable) {
sock.disconnect();
}
return reject(error);
});
try {
await connPromise;
} catch (error) {
sock = null;
throw error;
}
});
}

这就是测试的样子

const esl = require('modesl');
const eslModule = rewire(`<PATH TO MODULE>`);
(...)
it('It should return a valid response', async function () {

const cmd = "c";
const args = "t";
const ip = "127.0.0.1";
const port = '<port>'
const expResp = {
result: '+OK---- 00000000-0000-0000-0000-000000000000'
}
stub1 = sinon.stub(esl, 'Connection').yields(ip, port, 'pwd',expResp);
const result = await eslModule.exec(cmd, args, ip, port);
expect(result).resolves.to.deep.equal(expResp);
sinon.assert.calledOnce(stub1);
});

但我没有让它工作,因为测试进入了Promise,然后进入了sock.bgap,回复说无法访问未定义的bgapi。。。

如果我尝试模拟一个错误(在sock.on('error'…(中(,我会得到类似的回复,认为.on不是一个方法。

您需要在方法上伪造bgapi

这只是一个例子:我根据您的代码创建文件eslModule.js。

// File eslModule.js
const esl = require('modesl');
async function exec(cmd, args, ip, port) {
return new Promise(function(resolve, reject) {
try {
sock = new esl.Connection(ip, port, 'pwd', function() {
sock.bgapi(cmd, function(result) {
if (sock && sock.socket.writable && sock.socket.readable) {
sock.disconnect();
}
return resolve({
result: result.body
});
});
});
} catch (error) {
return reject(error);
}
sock.on('error', function(error) {
if (sock === null) {
return false;
}
if (error.code === 'ERR1' || error.code === 'ERR2') {
error.message = `Connection failed: [${error.code}]`;
}
if (sock && sock.socket.writable && sock.socket.readable) {
sock.disconnect();
}
return reject(error);
});
});
}
module.exports.exec = exec;

然后规范文件:eslModule.spec.js

// File: eslModule.spec.js
const esl = require('modesl');
const sinon = require('sinon');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const eslModule = require('./eslModule');
chai.use(chaiAsPromised);
const { expect } = chai;
it('It should return a valid response', function () {
const cmd = 'c';
const args = 't';
const ip = '127.0.0.1';
const port = '<port>';
// Define output.
const expResp = {
result: '+OK---- 00000000-0000-0000-0000-000000000000',
};
// Prepare variable to store callback function.
let connectionCallback;
let bgApiCallback;
// Create fake sock.
const sockFake = {
bgapi: sinon.fake((arg1, arg2) => {
bgApiCallback = arg2;
}),
socket: {
writable: true,
readble: true,
},
disconnect: sinon.fake(),
on: sinon.fake(),
};
// Create stub on esl.Connection.
const stubEslConnection = sinon.stub(esl, 'Connection');
stubEslConnection.callsFake((arg1, arg2, arg3, arg4) => {
connectionCallback = arg4;
return sockFake;
});
// Call exec function.
const result = eslModule.exec(cmd, args, ip, port);
// Make sure all callback function get called.
connectionCallback();
bgApiCallback({ body: expResp.result });
// Result is Promise object, use with eventually.
expect(result).eventually.to.deep.equal(expResp);
// Makesure stub get called.
expect(stubEslConnection.calledOnce).to.equal(true);
// Do not forget to restore the stub.
stubEslConnection.restore();
});

当我在终端上使用摩卡运行它时

$ npx mocha eslModule.spec.js 

✓ It should return a valid response
1 passing (4ms)

注:

  • 我从不使用modesl模块,我纯粹基于您的代码示例创建上面的测试
  • 我选择按照承诺使用chai,而不是让它发挥异步功能
  • 规范文件中最棘手的事情是:创建假sock对象并处理回调函数

最新更新