测试异步函数
在Jest中测试异步函数主要有4种方法:
- 在
test中返回的Promise中断言 - 使用
async和await - 在回调函数中使用
done函数 - 使用
resolves和rejects
返回Promise
如果要测试的函数返回的是一个Promise,那么我们就可以让test返回Promise,在Promise中使用断言。比如:
test('the data is peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
})
})
这样,我们就可以测试这个Promise函数了。
注意:我们一定要返回
Promise,让Jest知道这是一个异步函数,在Promise的resolve后进行断言,否则,Jest会提前断言。这个时候,Promise的状态还没有改变,得不到我们想要的结果。如果Promise没有resolve,而是jest了,那么测试会直接失败。
async/await
在测试异步代码的时候,我们可以直接使用async和await。就像下面一样:
test('the data is peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
})
test('the fetch fails with an error', async () => {
expect.assertions(1);
try {
await fetchData();
} catch (e) {
expect(e).toMatch('error');
}
})
在使用async/await测试异步代码的时候,我们要给test函数添加async标记,在异步代码前使用await。
当使用async/await测试异步代码失败的时候,记得一定要使用assertions来断言测试有过断言,否则测试不能通过。
使用回调函数
如果我们要测试的异步代码是在回调函数中,而不是在Promise里,那么我们就需要使用test函数中单参数done来解决问题了。比如:
test('the data is peanut butter', done => {
function callback(error, data) {
if (error) {
done(error);
return;
}
try {
expect(data).toBe('peanut butter');
done();
} catch (error) {
done(error);
}
}
fetchData(callback);
})
在这个例子中,如果done()函数从来没有执行过,那么测试会超时失败。
如果expect执行失败,那么其将抛出一个错误,其后的done
就不会执行。如果我们想要知道具体为什么会失败,那么我们就要在测试中捕获这个错误。所以需要把expect放入try中,然后在catch
中捕获错误,使用done来接收error的值。
使用resolves和rejects
我们也可以让test中的函数返回一个resolves或rejects来测试异步代码。比如:
test('the data is peanut butter', () => {
return expect(fetchData()).resolves().toBe('peanut butter');
})
直接通过resolves来声明我们期望Promise的状态会变为resolve状态,并返回peanut butter,否则测试失败(无论Promise
是变为reject还是resolve后返回的不是peanut butter)。
同理,通过rejects,我们期望Promise的状态会变为rejects,并返回一个指定的错误。如:
test('the fetch fails with an error', () => {
return expect(fetchData()).rejects.toMatch('error');
})
测试RxJs中Promise的行为
因为RxJs的实现机制和Promise微任务的问题,在RxJs中不能使用弹珠测试,那么我们就要使用Jest中测试异步代码中的方法来解决问题了。比如:
// Some RxJS code that also consumes a Promise, so TestScheduler won't be able
// to correctly virtualize and the test will always be really asynchronous.
const myAsyncCode = () => from(Promise.resolve('something'));
it('has async code', (done) => {
myAsyncCode().subscribe((d) => {
assertEqual(d, 'something');
done();
});
});