Javascript 模拟实现抛出错误后的Jest spyOn调用计数
我有一个程序,可以按此顺序发出三个Javascript 模拟实现抛出错误后的Jest spyOn调用计数,javascript,unit-testing,jestjs,Javascript,Unit Testing,Jestjs,我有一个程序,可以按此顺序发出三个post请求 http://myservice/login http://myservice/upload http://myservice/logout 代码看起来像这样 async main() { try { await this.login() await this.upload() } catch (e) { throw e } finally { await th
post
请求
async main() {
try {
await this.login()
await this.upload()
} catch (e) {
throw e
} finally {
await this.logout()
}
}
每个方法在失败时抛出自己的错误
我使用Jest监视底层请求库(superagent)。对于一个特定的测试,我想测试如果上传函数抛出错误,是否发出注销post
请求
我通过抛出异常模拟post
请求
const superagentStub = {
post: () => superagentStub
}
const postSpy = jest.spyOn(superagent, 'post')
.mockImplementationOnce(() => superagentStub)
.mockImplementationOnce(() => { throw new Error() })
.mockImplementationOnce(() => superagentStub)
const instance = new ExampleProgram();
expect(async () => await instance.main()).rejects.toThrow(); // This is fine
expect(postSpy).toHaveBeenNthCalledWith(3, 'http://myservice/logout')
如果我不模拟第三个实现,测试将失败,因为logout()
将抛出自己的错误,因为第三个post
请求将作为实时调用失败
本例中的spy报告只对底层库的post
方法进行了一次调用
http://myservice/login
我觉得这很奇怪,因为我期待着给间谍打3个电话
http://myservice/login
http://myservice/upload ->但它抛出了一个错误
http://myservice/logout
请记住如何使用expect(…).rejects.toThrow()
。不过,这有点棘手:
顺便说一句:在使用JavaScript编码时,让ESLint处于活动状态总是很好的。然后,以下规则可能会警告您错误:(“必须等待或返回异步断言。”)
解决方案
测试代码最后一行的第二行开头缺少一个wait
。用以下内容替换该行有望解决您的问题:
wait expect(()=>instance.main()).rejects.toThrow();
这和
await expect(async()=>await instance.main()).rejects.toThrow();
您声明//在您的变体中这很好,但实际上并非如此。你有一个“假阳性”,在那里。Jest很可能也会接受测试的最后一行,即使您否定它,也就是说,如果您将.rejects.toThrow()
替换为.rejects.not.toThrow()
如果在同一个测试套件中有多个测试,Jest可能会声明稍后的某个测试失败,即使它实际上是导致问题的第一个测试
细节
如果给定行开头没有新的wait
,则会发生以下情况:
expect(…).rejects.toThrow()
启动instance.main()
-但不等待创建的承诺解决或拒绝
instance.main()
的开头将同步运行到第一个wait
,即调用this.login()
主要是因为对superagent.post()
的模拟是同步的,this.login()
将立即返回。顺便说一句:最好总是用异步模型替换异步函数,例如使用.mockResolvedValueOnce()
承诺仍然悬而未决;JavaScript现在运行测试代码的最后一行,Jest声明您的模型只使用过一次(到目前为止)
由于该错误,测试被中止
对instance.main()
的调用很可能会在之后继续,导致instance.main()
中出现预期的错误,一个被拒绝的承诺和三次模型使用-但测试失败后所有这些都已失败
是的,确实如此!我们的linter已经启用了有效的expect
,但是没有alwaysAwait
,因此感谢您指出,我和其他人都明白了