如何断言与 sinon 和 chai 的承诺
how to assert catch promise with sinon and chai
我们的 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');
});
});
有些东西需要修复源文件和测试文件。
对于源文件,我们必须使用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,我们必须确保 return 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);
});
};
希望对您有所帮助
在测试您的断言之前,您需要能够 await
exports.handler
的结果。你 正在 等待它,但是 exports.handler
没有返回承诺,所以在测试中没有什么等待 — exports.handler
returns 立即未定义所以在可以调用 console.error
之前,测试在同一事件循环中运行断言。
我不确定为什么您在 promise 解决的测试中没有看到类似的问题。 (也许值得检查该测试是否正确失败)
这应该有帮助:
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)...
通过这些更改,我的测试通过了,但(更重要的是)当我没有在 catch
中调用 console.error
时,测试失败了。
我们的 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');
});
});
有些东西需要修复源文件和测试文件。
对于源文件,我们必须使用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,我们必须确保 return 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);
});
};
希望对您有所帮助
在测试您的断言之前,您需要能够 await
exports.handler
的结果。你 正在 等待它,但是 exports.handler
没有返回承诺,所以在测试中没有什么等待 — exports.handler
returns 立即未定义所以在可以调用 console.error
之前,测试在同一事件循环中运行断言。
我不确定为什么您在 promise 解决的测试中没有看到类似的问题。 (也许值得检查该测试是否正确失败)
这应该有帮助:
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)...
通过这些更改,我的测试通过了,但(更重要的是)当我没有在 catch
中调用 console.error
时,测试失败了。