我有一门拒绝承诺的课程:
Sync.prototype.doCall = function(verb, method, data) {
var self = this;
self.client = P.promisifyAll(new Client());
var res = this.queue.then(function() {
return self.client.callAsync(verb, method, data)
.then(function(res) {
return;
})
.catch(function(err) {
// This is what gets called in my test
return P.reject('Boo');
});
});
this.queue = res.delay(this.options.throttle * 1000);
return res;
};
Sync.prototype.sendNote = function(data) {
var self = this;
return self.doCall('POST', '/Invoice', {
Invoice: data
}).then(function(res) {
return data;
});
};
在我的测试中:
return expect(s.sendNote(data)).to.eventually.be.rejectedWith('Boo');
但是,当测试通过时,它会将错误抛出到控制台。
未处理的拒绝错误:Boo ...
对于非承诺错误,我使用绑定来测试,以防止抛出错误,直到 Chai 可以包装和测试:
return expect(s.sendNote.bind(s, data)).to.eventually.be.rejectedWith('Boo');
但是这不起作用并返回:
类型错误:
[Function] is not a thenable.
正确的测试方法是什么?
(免责声明:即使对于不使用 Bluebird 的人来说,这也是一个很好的问题。我在here发布了类似的答案;这个答案适用于不使用 Bluebird 的人。)
以下是如何使用 chai-as-promised 来测试 Promise 的
resolve
和 reject
情况:
var chai = require('chai');
var expect = chai.expect;
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);
...
it('resolves as promised', function() {
return expect(Promise.resolve('woof')).to.eventually.equal('woof');
});
it('rejects as promised', function() {
return expect(Promise.reject('caw')).to.be.rejectedWith('caw');
});
您可以在没有承诺的情况下完成相同的任务,如下所示:
it('resolves as promised', function() {
return Promise.resolve("woof")
.then(function(m) { expect(m).to.equal('woof'); })
.catch(function(e) { throw e }) // use error thrown by test suite
;
});
it('rejects as promised', function() {
return Promise.reject("caw")
.then(function(m) { throw new Error('was not supposed to succeed'); })
.catch(function(m) { expect(m).to.equal('caw'); })
;
});
我个人用这个习语:
it('rejects as promised', function() {
return Promise.reject("caw")
.then(
(m) => { assert.fail('was not supposed to succeed'); }
(m) => { /* some extra tests here */ }
);
});
这是极少数情况之一
then(onFulfilled, onRejected)
(2 个参数)可以合法使用。
如果您按照其他答案中的建议链接
.then(reject).catch(onRejected)
,您最终会每次进入
catch
处理程序,因为它也会捕获前面的 then
处理程序中产生的拒绝 - 这可能会导致常绿测试如果你不够仔细检查这种可能性。
您收到错误是因为 sendNote 被拒绝而您没有捕获它。
尝试:
var callPromise = self.doCall('POST', '/Invoice', {
Invoice: data
}).then(function(res) {
return data;
});
callPromise.catch(function(reason) {
console.info('sendNote failed with reason:', reason);
});
return callPromise;
看来您还必须将现有的捕获一块移出:
var res = this.queue.then(function() {
return self.client.callAsync(verb, method, data)
.then(function(res) {
return;
});
}).catch(function(err) {
// This is what gets called in my test
return P.reject('Boo');
});
通用辅助函数:
import { assert } from 'chai'
const assertThrowsAsync = async(fn, expectedMessage) => {
try {
await fn()
} catch (err) {
if (expectedMessage) {
assert.include(err.message, expectedMessage, `Function failed as expected, but could not find message snippet '${expectedMessage}'`)
}
return
}
assert.fail('function did not throw as expected')
}
这样称呼它:
describe('demo', () => {
it('negative: inacceptable path', async() => {
await assertThrowsAsync(async() => {
await someFuntionOfMine({}, ['/really/bad/path'])
}, 'acceptable path')
})
...
回到这个话题,因为我在谷歌搜索后来到了这里。
Node自己的
assert
模块有拒绝方法:
https://nodejs.org/docs/latest/api/assert.html#assertrejectsasyncfn-error-message
您可以在特定场景中使用它来代替 chai,以防止添加助手和/或额外的库。