在重构我们的Jest测试套件时,我发现了很多这样的事情:
it('calls the API and throws an error', async () => {
expect.assertions(2);
try {
await login('email', 'password');
} catch (error) {
expect(error.name).toEqual('Unauthorized');
expect(error.status).toEqual(401);
}
});
我认为expect.assertions(2)
行在这里是多余的,可以安全删除,因为我们已经await
对login()
进行了异步调用。
我是否正确,或者我误解了expect.assertions
的工作原理?
答案 0 :(得分:7)
expect.assertions
在测试异步代码的错误情况时很重要,并且不是多余的。
如果从示例中删除expect.assertions
,您将无法确定login
确实引发了错误。
it('calls the API and throws an error', async () => {
try {
await login('email', 'password');
} catch (error) {
expect(error.name).toEqual('Unauthorized');
expect(error.status).toEqual(401);
}
});
假设某人根据其他逻辑更改了login
的行为以引发错误,或者某人影响了此测试的模拟,而该模拟不再导致login
抛出。 catch
块中的断言不会运行,但测试仍会通过。
在测试开始时使用expect.assertions
可确保如果catch内的断言不运行,则会导致失败。
答案 1 :(得分:2)
这是来自Jest文档:
Expect.assertions(number)验证一定数量的断言 在测试期间调用。这在测试时通常很有用 异步代码,以确保回调中的断言 实际上被召唤了。
换句话说,expect.assertions 确保在运行测试时发出n个断言。
特别是在编写新测试时,使用它很有用,因此可以轻松检查测试期间是否进行了正确的断言。异步测试很容易通过,因为在测试之前没有做出预期的断言,认为它已经准备好了。
如果您确信您的测试按预期工作,那么它们肯定会被删除。
答案 2 :(得分:1)
我必须承认,除了错误测试之外,我发现很难看到 expect.assertions
的真正用途。上面的代码段可以在相同的保证下更改为以下代码,但我认为它读起来更自然,不需要我计算调用 expect
的次数。如果测试很复杂,这尤其容易出错:
it('calls the API and throws an error', async () => {
try {
await login('email', 'password');
fail('must throw')
} catch (error) {
expect(error.name).toEqual('Unauthorized');
expect(error.status).toEqual(401);
}
});
答案 3 :(得分:0)
要确保对异步/等待测试的catch块中的断言进行了充分的测试,必须按照代码片段中的说明声明expect.assertions(n)
。对于没有catch块的异步/等待测试,不需要这样的声明。
这似乎很不直观,但这只是事实。也许,由于某些原因,在JavaScript运行时的深处,测试环境可以检测到何时成功解决了一个等待的诺言,但无法检测到未能解决的等待的诺言。测试环境的创建者可能会逐字知道为什么会这样。
答案 4 :(得分:0)
我认为我们在这里遗漏了显而易见的东西。
expect.assertions(3) 只是说 ...
我希望在测试超时之前调用 3 个期望语句。例如
expect(actual1).toEqual(expected1);
expect(actual2).toEqual(expected2);
expect(actual3).toEqual(expected3);
这种超时业务是使用expect.assertions的原因。在纯同步测试中使用它是愚蠢的。至少可以在规范文件中的订阅块(或其他异步块)中找到一个 expect 语句。