以下测试表现得很奇怪:
it('Should return the exchange rates for btc_ltc', function(done) {
var pair = 'btc_ltc';
shapeshift.getRate(pair)
.then(function(data){
expect(data.pair).to.equal(pair);
expect(data.rate).to.have.length(400);
done();
})
.catch(function(err){
//this should really be `.catch` for a failed request, but
//instead it looks like chai is picking this up when a test fails
done(err);
})
});
我应该如何正确处理被拒绝的承诺(并对其进行测试)?
我应该如何正确处理失败的测试(即:expect(data.rate).to.have.length(400);
?
以下是我正在测试的实现:
var requestp = require('request-promise');
var shapeshift = module.exports = {};
var url = 'http://shapeshift.io';
shapeshift.getRate = function(pair){
return requestp({
url: url + '/rate/' + pair,
json: true
});
};
答案 0 :(得分:214)
最简单的方法是使用Mocha在最新版本中支持的内置承诺:
it('Should return the exchange rates for btc_ltc', function() { // no done
var pair = 'btc_ltc';
// note the return
return shapeshift.getRate(pair).then(function(data){
expect(data.pair).to.equal(pair);
expect(data.rate).to.have.length(400);
});// no catch, it'll figure it out since the promise is rejected
});
或者使用现代Node和async / await:
it('Should return the exchange rates for btc_ltc', async () => { // no done
const pair = 'btc_ltc';
const data = await shapeshift.getRate(pair);
expect(data.pair).to.equal(pair);
expect(data.rate).to.have.length(400);
});
由于这种方法是端到端的承诺,因此更容易测试,你不必考虑你正在思考的奇怪案例,就像所有奇怪的done()
调用一样。
这是Mocha目前在Jasmine等其他图书馆的优势。您可能还想检查Chai As Promised哪个更容易(没有.then
),但我个人更喜欢当前版本的清晰度和简洁性
答案 1 :(得分:36)
正如已经指出here,新版本的Mocha已经是Promise-aware。但是由于OP专门询问了Chai,所以指出chai-as-promised
包提供了一个干净的语法来测试承诺是公平的:
以下是如何使用chai-as-promised来测试承诺的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(m) { throw new Error('was not supposed to fail'); })
;
});
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'); })
;
});
答案 2 :(得分:2)
async/await
延迟承诺函数,如果延迟为0,则失败:
const timeoutPromise = (time) => {
return new Promise((resolve, reject) => {
if (time === 0)
reject({ 'message': 'invalid time 0' })
setTimeout(() => resolve('done', time))
})
}
// ↓ ↓ ↓
it('promise selftest', async () => {
// positive test
let r = await timeoutPromise(500)
assert.equal(r, 'done')
// negative test
try {
await timeoutPromise(0)
// a failing assert here is a bad idea, since it would lead into the catch clause…
} catch (err) {
// optional, check for specific error (or error.type, error. message to contain …)
assert.deepEqual(err, { 'message': 'invalid time 0' })
return // this is important
}
assert.isOk(false, 'timeOut must throw')
log('last')
})
正面测试非常简单。意外的失败(由500→0
模拟)会随着拒绝的承诺升级而自动使测试失败。
否定测试使用try-catch-idea。但是:关于不希望的通过的“抱怨”仅在catch子句之后发生(这样,它不会最终出现在catch()子句中,从而引发更多但具有误导性的错误。
为使该策略起作用,必须从catch子句返回测试。如果您不想测试其他任何东西,请使用另一个it()块。
答案 3 :(得分:0)
Tehre是更好的解决方案。只需在catch块中完成即可返回错误。
// ...
it('fail', (done) => {
// any async call that will return a Promise
ajaxJson({})
.then((req) => {
expect(1).to.equal(11); //this will throw a error
done(); //this will resove the test if there is no error
}).catch((e) => {
done(e); //this will catch the thrown error
});
});
此测试将失败,并显示以下消息:AssertionError: expected 1 to equal 11