我有一个拒绝承诺的类:
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…
对于非承诺错误,我使用bind来测试,以防止抛出错误,直到Chai可以包装和测试:
return expect(s.sendNote.bind(s, data)).to.eventually.be.rejectedWith('Boo');
但是这不起作用,返回:
TypeError: [Function] is not a thenable.
正确的测试方法是什么?
(免责声明:即使对于不使用Bluebird的人来说,这也是一个很好的问题。我在这里贴了一个类似的答案;这个答案将适用于不使用Bluebird的人。
与chai-as-promised下面是如何使用chai-as- Promise来测试一个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');
});
没有chai-as-promised 如果没有chai-as-promise,你也可以做到同样的事情,像这样:
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;
看起来您还必须将现有的catch块移出:
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')
})
...