我们的CLI中有一个方法,该方法使用该方法向用户返回打印消息的承诺。
exports.handler = (argv) => {
let customUtils = new Utils(argv);
Utils.deploy()
.then(res => console.log(`Ressource was deployed`))
.catch(e => {
console.error(`Ressource was not deployed`);
console.error(e);
process.exit(1);
});
}
我们正在寻找一种方法来测试控制台错误并在deploy()
承诺被拒绝的情况下退出进程。
我们尝试使用沙盒存根,然后在异步测试中声明:
describe('when promise is errored', () => {
beforeEach(() => {
sandbox = sinon.createSandbox();
utilsStub = sandbox.stub(Utils.prototype, 'deploy').rejects('rejected');
processStub = sandbox.stub(process, 'exit');
consoleStub = sandbox.stub(console, 'error');
});
afterEach(() => {
sandbox.restore();
});
it('should call deploy and log the error before exiting', async () => {
await handler({});
expect(utilsStub).to.have.been.called;
expect(console.error).to.have.been.called;
});
});
此测试无效:AssertionError: expected error to have been called at least once, but it was never called
。
当我们expect(process.exit).to.have.been.called;
时也会发生同样的情况。从来没有叫过。
我们以相似的方式成功测试了then
部分:
describe('when promise is resolved', () => {
beforeEach(() => {
sandbox = sinon.createSandbox();
utilsStub = sandbox.stub(Utils.prototype, 'deploy').callsFake(() => Promise.resolve('some text'));
consoleStub = sandbox.stub(console, 'log');
});
afterEach(() => {
sandbox.restore();
});
it('should call deploy and print success message', async () => {
await handler({});
expect(utilsStub).to.have.been.called;
expect(console.log).to.have.been.calledWith('Ressource was deployed');
});
});
答案 0 :(得分:1)
有些事情可以修复源文件和测试文件。
对于源文件,我们必须使用customUtils
来调用deploy()
函数。由于可以使用async/await
,因此从Promise进行转换可以产生更好的代码。
exports.handler = async argv => { // put async
let customUtils = new Utils(argv);
try {
await customUtils.deploy(); // change to await and use customUtils
console.log(`Ressource was deployed`);
} catch (e) {
console.error(`Ressource was not deployed`);
console.error(e);
process.exit(1);
}
};
对于测试文件,没有任何变化
describe('when promise is errored', () => {
beforeEach(() => {
sandbox = sinon.createSandbox();
utilsStub = sandbox.stub(Utils.prototype, 'deploy').rejects('rejected');
processStub = sandbox.stub(process, 'exit');
consoleStub = sandbox.stub(console, 'error');
});
afterEach(() => {
sandbox.restore();
});
it('should call deploy and log the error before exiting', async () => {
await handler({});
expect(utilsStub).to.have.been.called;
expect(console.error).to.have.been.called;
expect(process.exit).to.have.been.called; // add it
});
});
已更新:
如果要仍然使用Promise,我们必须确保我们返回了Promise。
exports.handler = (argv) => {
let customUtils = new Utils(argv);
return customUtils.deploy() // <== specify return here
.then(res => console.log(`Ressource was deployed`))
.catch(e => {
console.error(`Ressource was not deployed`);
console.error(e);
process.exit(1);
});
};
希望有帮助
答案 1 :(得分:1)
在测试您的断言之前,您需要await
的结果exports.handler
。您正在 等待中,但是exports.handler
没有返回承诺,因此测试中没有等待的地方-exports.handler
立即返回undefined,因此测试以相同的方式运行断言console.error
之前的事件循环。
我不确定为什么在诺言解决的测试中您没有看到类似的问题。 (也许值得检查该测试是否正确失败)
这应该有帮助:
exports.handler = (argv) => {
let customUtils = new Utils(argv);
//Utils.deploy() // <- is that a typo?
return customUtils.deploy()
.then(res => console.log(`Ressource was deployed`))
.catch(e => {
console.error(`Ressource was not deployed`);
console.error(e);
process.exit(1);
});
}
在测试中,您还将使用以下方式创建间谍:
consoleStub = sandbox.stub(console, 'error');
但是直接在console.error
上写断言。我认为这不起作用:
expect(console.error).to.have.been.called;
// maybe expect(consoleStub)...
有了这些更改,测试对我来说就通过了,(更重要的是)当我没有在console.error
中调用catch
时,测试失败了。