1. 异步测试哪里特殊?
在JavaScript中执行异步代码是很常见的。当你有以异步方式运行的代码时,Jest 需要知道当前它测试的代码是否已完成,然后它可以转移到另一个测试。
经典错误:
function fetchData(callback) {
setTimeout(() => callback('peanut butter'), 5 * 1000);
}
// 经典错误
test('the data is peanut butter', () => {
function callback(data) {
expect(data).toBe('peanut butter');
}
fetchData(callback);
});
2. 异步测试基本模式
2.1. test('...', (done) => {...}) 模式
function fetchData(callback) {
setTimeout(() => callback('peanut butter'), 5 * 1000);
}
test('the data is peanut butter', (done) => {
function callback(data) {
expect(data).toBe('peanut butter');
done();
}
fetchData(callback);
});
2.2. Promise 模式
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve('peanut butter'), 5 * 1000);
});
}
test('the data is peanut butter', () => {
return fetchData().then((data)=>{
expect(data).toBe('peanut butter');
});
});
2.3. Async|Await 模式
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve('peanut butter'), 5 * 1000);
});
}
test('the data is peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});
3. expect.hasAssertions()、expect.assertions(number)
观察一个例子:
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve('peanut butter'), 5 * 1000);
});
}
test('the data is peanut butter', async () => {
try {
await fetchData();
} catch (e) {
expect(e).toMatch('error');
}
});
这个例子中,显然,代码不会运行到 "expect(e).toMatch('error')",但测试用例还是通过了,这显然不是我们想要的。
修改一下例子:
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve('peanut butter'), 5 * 1000);
});
}
test('the data is peanut butter', async () => {
expect.hasAssertions(); // 划重点
try {
await fetchData();
} catch (e) {
expect(e).toMatch('error');
}
});
再观察一个例子:
function doAsync(callback1, callback2) {
callback1(true);
}
test('the data is peanut butter', async () => {
expect.assertions(2); // 划重点
function callback1(data) {
expect(data).toBeTruthy();
}
function callback2(data) {
expect(data).toBeTruthy();
}
doAsync(callback1, callback2);
});
4. .resolves、.rejects
示例1:
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve('peanut butter'), 6 * 1000);
});
}
test('the data is peanut butter', () => {
return expect(fetchData()).resolves.toBe('peanut butter');
});
示例2:
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('peanut butter'));
}, 3 * 1000);
});
}
test('the data is peanut butter', async () => {
return expect(fetchData()).rejects.toThrow("peanut butter");
});
示例3:
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 3 * 1000);
}).then(()=>{
throw new Error('peanut butter');
});
}
test('the data is peanut butter', () => {
return expect(fetchData()).rejects.toThrow("peanut butter");
});
参考:
Jest Matchers: https://jestjs.io/docs/en/using-matchers Jest Expect API: https://jestjs.io/docs/zh-Hans/expect An Async Example: https://jestjs.io/docs/en/tutorial-async