Jest重点难点 - 异步代码的测试

网友投稿 288 2022-09-27

Jest重点难点 - 异步代码的测试

Jest的文档有时候晦涩难懂,中文文档又有股浓浓的机翻味,因此将自己的学习笔记整理出来,融入自己的一些理解,力争做到通俗易懂。后面还会整理函数模拟,计时器模拟等内容,希望对大家有所帮助。

回调函数

需在回调函数中调用​​done​​函数,Jest会在​​done​​函数执行结束后,结束测试。

function fetchData(fn) { setTimeout(() => { fn('Hello world') }, 1000);}test('callback', (done) => { function callback(data) { expect(data).toBe('Hello world') done() // 在回调函数中记得调用done函数,不然测试用例将无法通过,显示超时错误。 } fetchData(callback)})复制代码

如果​​done()​​ 函数从未被调用,测试用例会显示超时错误!!!

下面修改一下测试用例,将​​expect(data).toBe('Hello world')​​​ 改为 ​​expect(data).toBe('Hello Jest')​​。

test('callback', (done) => { function callback(data) { expect(data).toBe('Hello Jest') done() } fetchData(callback)})复制代码

显然这是不能通过测试的,但是Jest给我们的提示却是​​thrown: "Exceeded timeout of 5000 ms for a test……​​​,即超时错误。这是因为​​expect​​​执行失败后,会抛出一个错误,导致后面的 ​​done()​​​ 不再执行,从而显示超时。如果我们想知道测试用例失败的原因,需要将 ​​expect​​​ 放入 ​​try​​​ 中,然后将 ​​error​​​ 传递给 ​​catch​​​ 中的 ​​done​​函数。

因此,完善的测试用例应该如下:

test('callback', done => { function callback(data) { try { expect(data).toBe('Hello Jest') done() } catch (error) { done(error) } } fetchData(callback)});复制代码

Promise

如果异步代码使用了 Promise,需要在测试用例中将Promise对象返回

function fetchData() { return new Promise((resolve) => { setTimeout(() => { resolve('Hello world') }, 1000); })}test('Promise', () => { // 一定记得加上 return,否则测试在 fetchData 执行完成之前就已经结束,随后then中的expect也不会执行,会导致超时错误!!! return fetchData().then(data => { expect(data).toBe('Hello world') })})复制代码

如果需要测试​​reject​​状态的Promise,除了需要在​​catch​​方法中执行断言外,还需要使用​​expect.assertions​​来验证是否调用了指定次数的断言。

比如,我们需要测试接口失败时返回的数据。先修改​​fetchData​​​函数,通过传入的​​success​​参数来模拟接口的成功和失败。

function fetchData(success) { return success ? Promise.resolve('success message') : Promise.reject('error message')}复制代码

如果接口返回失败的情况下,此时以下的测试用例时可以通过的,这没有问题。

test('Promise rejected', () => { return fetchData(false).catch(error => { expect(error).toBe('error message') // 测试通过 })})复制代码

但是如果接口返回成功,其实测试用例也是可以通过的。这是因为接口成功的话,是不会执行​​catch​​​函数的。那么​​ catch​​ 里面的断言也就不会被执行,所以能通过测试。看下面的例子:

test('Promise rejected', () => { // 接口成功,因为不会执行catch return fetchData(true).catch(error => { expect(error).toBe('error message') // 测试通过 })})复制代码

可是这并不符合我们的预期啊,我们就是想测试接口失败时的数据,此时,我们可以使用​​expect.assertions(1)​​​,这样就可以知道,至少有一次​​expect​​​被执行,也就是​​catch​​​一定会被执行,那么,​​fetchData​​​一定要是返回失败的,而不是成功的,因此我们要修改测试用例,将​​fetchData(true)​​​改为​​fetchData(false)​​,来确保接口是返回是失败的,这样才是严谨的测试用例。

test('Promise rejected', () => { expect.assertions(1) // 至少执行一次 expect // 将fetchData(true)改为fetchData(false),接口失败才能执行catch里面的断言 return fetchData(false).catch(error => { expect(error).toBe('error message') // 测试通过, })})复制代码

当测试 promise 的时候,特别是测试 catch,一定要加 expect.assertions() 确保测试代码会执行

resolves 和 rejects 匹配器

​​resolves​​​和​​rejects​​匹配器可以让我们很方便的测试Promise。当然不要忘记将整个断言作为返回值返回

test('the data is success message', () => { // 不要忘记将整个断言作为返回值返回 return expect(fetchData(true)).resolves.toBe('success message')});test('the fetch fails with an error', () => { // 不要忘记将整个断言作为返回值返回 return expect(fetchData(false)).resolves.toBe('error message')});复制代码

async 和 await

我们也可以在测试中使用​​async​​​ 和 ​​await​​​,写异步测试用例时,可以在传递给​​test​​​的函数前面加上​​async​​。

test('the data is success message', async () => { const data = await fetchData(true) expect(data).toBe('success message')});test('the fetch fails with an error', async () => { expect.assertions(1) try { await fetchData(false) } catch (e) { expect(e).toBe('error message') }});复制代码

你也可以将 ​​async​​​ and ​​await​​​和 ​​resolves​​​ or ​​rejects​​一起使用。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:详解MybatisPlus中@Version注解的使用
下一篇:JS执行器在UI自动化测试中的应用
相关文章

 发表评论

暂时没有评论,来抢沙发吧~