ple*_*xer 21 mocha.js node.js async-await chai chai-as-promised
我正在努力找出在使用async/await时在Mocha测试中验证承诺被拒绝的最佳方法.
这是一个有效的例子,但我不喜欢should.be.rejectedWith返回一个需要从测试函数返回的promise才能正确评估.使用async/await删除了测试值的这个要求(正如我对wins()下面的结果所做的那样),我觉得很可能在某些时候会忘记return语句,在这种情况下测试将始终通过.
// Always succeeds
function wins() {
return new Promise(function(resolve, reject) {
resolve('Winner');
});
}
// Always fails with an error
function fails() {
return new Promise(function(resolve, reject) {
reject('Contrived Error');
});
}
it('throws an error', async () => {
let r = await wins();
r.should.equal('Winner');
return fails().should.be.rejectedWith('Contrived Error');
});
Run Code Online (Sandbox Code Playgroud)
感觉应该可以使用async/await将拒绝转换为异常的事实并将其与Chai的should.throw相结合,但我无法确定正确的语法.
理想情况下这可行,但似乎不是:
it('throws an error', async () => {
let r = await wins();
r.should.equal('Winner');
(await fails()).should.throw(Error);
});
Run Code Online (Sandbox Code Playgroud)
Ada*_*ian 25
这种方法的问题是(await fails()).should.throw(Error)没有意义.
await解决了Promise.如果Promise拒绝,它会抛出被拒绝的值.
因此(await fails()).should.throw(Error)永远不会工作:如果fails()拒绝,则抛出错误,并且.should.throw(Error)永远不会执行.
您最常用的选择是使用Chai的rejectedWith属性,如您在问题中所示.
这是一个简单的例子.与你在问题中所展示的内容没什么不同; 我只是用async的功能wins()和fails()和expect代替should.当然,你可以使用返回a Promise并且chai.should很好的函数.
const chai = require('chai')
const expect = chai.expect
chai.use(require('chai-as-promised'))
// Always succeeds
async function wins() {
return 'Winner'
}
// Always fails with an error
async function fails() {
throw new Error('Contrived Error')
}
it('wins() returns Winner', async () => {
expect(await wins()).to.equal('Winner')
})
it('fails() throws Error', async () => {
await expect(fails()).to.be.rejectedWith(Error)
})
Run Code Online (Sandbox Code Playgroud)
如果您希望您wins()的fails()测试更接近您的测试,您可以wins()像这样编写测试:
it('wins() returns Winner', async () => {
await expect(wins()).to.eventually.equal('Winner')
})
Run Code Online (Sandbox Code Playgroud)
在这两个例子中要记住的关键是chai-as-promised返回承诺其功能,如rejectedWith和eventually.something.因此,您必须await在async测试函数的上下文中,否则失败的条件仍将通过:
async function wins() {
return 'Loser'
}
async function fails() {
return 'Winner'
}
it('wins() returns Winner', async () => {
expect(wins()).to.eventually.equal('Winner')
})
it('fails() throws Error', async () => {
expect(fails()).to.be.rejectedWith(Error)
})
Run Code Online (Sandbox Code Playgroud)
如果您使用上面的代码运行测试,您将获得以下内容:
$ npm test
> mocha-chai-async@1.0.0 test /home/vsimonian/code/mocha-chai-async
> mocha .
? wins() returns Winner
(node:13836) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rej
ection id: 1): AssertionError: expected 'Loser' to equal 'Winner'
(node:13836) [DEP0018] DeprecationWarning: Unhandled promise rejections are dep
recated. In the future, promise rejections that are not handled will terminate
the Node.js process with a non-zero exit code.
? fails() throws Error
(node:13836) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rej
ection id: 2): AssertionError: expected promise to be rejected with 'Error' but
it was fulfilled with 'Winner'
2 passing (11ms)
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,chai断言实际上已经失败了,但它们在Promise的背景下失败了,没有人await编辑或catch编辑过.因此,Mocha没有看到任何失败,并将测试标记为好像已经通过,但Node.js(如上所述,将来会改变的行为)将未处理的拒绝打印到终端.
kor*_*ord 21
我使用这样的自定义函数:
const expectThrowsAsync = async (method, errorMessage) => {
let error = null
try {
await method()
}
catch (err) {
error = err
}
expect(error).to.be.an('Error')
if (errorMessage) {
expect(error.message).to.equal(errorMessage)
}
}
Run Code Online (Sandbox Code Playgroud)
然后,对于常规的异步函数,例如:
const login = async (username, password) => {
if (!username || !password) {
throw new Error("Invalid username or password")
}
//await service.login(username, password)
}
Run Code Online (Sandbox Code Playgroud)
我写这样的测试:
describe('login tests', () => {
it('should throw validation error when not providing username or passsword', async () => {
await expectThrowsAsync(() => login())
await expectThrowsAsync(() => login(), "Invalid username or password")
await expectThrowsAsync(() => login("username"))
await expectThrowsAsync(() => login("username"), "Invalid username or password")
await expectThrowsAsync(() => login(null, "password"))
await expectThrowsAsync(() => login(null, "password"), "Invalid username or password")
//login("username","password") will not throw an exception, so expectation will fail
//await expectThrowsAsync(() => login("username", "password"))
})
})
Run Code Online (Sandbox Code Playgroud)
Ale*_*yuv 12
npm i chai-as-promised -Dimport chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);
const expect = chai.expect;
describe('MY_DESCR', () => {
it('MY_TEST', async () => {
expect(myAsyncFunctionThatWillReject()).to.eventually.be.rejected;
});
});
Run Code Online (Sandbox Code Playgroud)
此示例仅适用于 Node!
当您在 Node.js 上使用 Mocha 时,您可以使用doesNotReject()或rejects()两者都需要一个返回承诺的函数。
何时应该拒绝的示例:
await rejects(testFunction());
Run Code Online (Sandbox Code Playgroud)
请参阅:https : //nodejs.org/api/assert.html#assert_assert_rejects_asyncfn_error_message
不应拒绝的示例:
await doesNotReject(testFunction());
Run Code Online (Sandbox Code Playgroud)
见:https : //nodejs.org/api/assert.html#assert_assert_doesnotreject_asyncfn_error_message
您可以使用async/await和should进行简单的验证
it('should not throw an error', async () => {
try {
let r = await wins();
r.should.equal('Winner');
} catch (error) {
error.should.be.null(); //should.not.exist(error) can also be used
}
});
it('throws an error', async () => {
try {
await fails();
} catch (error) {
error.should.be.Error();
error.should.have.value("message", "Contrived Error");
}
});
Run Code Online (Sandbox Code Playgroud)