Jest 测试异步函数
异步编程的发展历史
异步函数,就不用我描述了,JS是单线程的,所以没有办法处理异步问题,但是可以通过其他的机制实现
回调函数
例如,我们写一个定时器,在函数fetchData中,有一个延时处理的函数,但是,你有不能等他,如果他是一年呢?
所以,我们给他一个回调函数,来等他执行完返回处理结果,所以依次输出了 "开始获取数据....","数据获取完成",以及"获取的数据"
function fetchData(callback) {
console.log("开始获取数据...");
setTimeout(() => {
const data = { id: 1, name: "Alice" }; // 模拟从服务器返回的数据
console.log("数据获取完成");
callback(null, data); // 使用回调函数传递结果
}, 2000);
}
// 调用函数并处理结果
fetchData((error, result) => {
if (error) {
console.error("发生错误:", error);
} else {
console.log("获取到的数据:", result);
}
});
Promise
回调函数的弊端其实是很大的,回调地狱(Callback Hell)的问题是最大的.
当多个异步任务需要依次执行时,回调函数会不断嵌套,导致代码层级越来越深,难以维护和阅读,到最后你都不知道哪里是那里的数据了.
并且.他的错误处理机制,无法使用同步的问题等都是巨大的隐患.
setTimeout(() => {
console.log("第一步完成");
setTimeout(() => {
console.log("第二步完成");
setTimeout(() => {
console.log("第三步完成");
}, 1000);
}, 1000);
}, 1000);
所以才出现了Promise(承诺),他的意思也很简单,就是我等你
Promise 接收两个参数,一个是resolve成功,一个是reject失败
resolve:成功时调用,将结果传递给 then
reject:失败时调用,将错误传递给 catch
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = true; // 模拟成功或失败
if (success) {
resolve("操作成功");
} else {
reject("操作失败");
}
}, 1000);
});
// 使用 then 和 catch 处理结果
promise
.then((result) => {
console.log("成功:", result);
})
.catch((error) => {
console.error("失败:", error);
});
虽然你看起来,他没有什么变化,但是他不仅给你提供了优秀的错误处理机制,而且它可以进行链式调用,也就是说,你可以一直使用.then,或.catch.
再后来,我们又有了async和await语法,他们的出现就仅仅是让你的代码看起来同步的一样
传统写法
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve("数据加载完成"), 1000);
});
}
fetchData()
.then((result) => {
console.log(result);
return "下一步操作";
})
.then((nextResult) => {
console.log(nextResult);
})
.catch((err) => {
console.error(err);
});
新的写法
async function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve("数据加载完成"), 1000);
});
}
async function run() {
try {
const result = await fetchData();
console.log(result);
const nextResult = "下一步操作";
console.log(nextResult);
} catch (err) {
console.error(err);
}
}
run();
asycn标识是异步函数,await表明等待他的执行结果
Jest测试异步
Jest怎么测试异步函数的呢?分几种情况的呢
Promise
这种是返回一个Promise的情况
异步函数
import axios from 'axios';
// 返回一个promise
export const axiosData = () => {
return axios.get('http://www.dell-lee.com/react/api/demo.json')
.then((res) => res.data) // 返回响应的数据
.catch((error) => {
throw new Error('Error fetching data'); // 如果请求失败,抛出错误
});
};
测试函数
import axios from "axios";
import {axiosData} from "./main";
// 模拟 axios 请求
jest.mock("axios");
// 使用async 解决异步函数测试
test.only("axiosData 获取数据", async () => {
// 设置模拟的返回数据
axios.get.mockResolvedValue({data: {success: true}});
// 使用 async/await 处理异步函数
const data = await axiosData(); // 假设 axiosData 内部可以直接返回 Promise
expect(data).toEqual({success: true});
});
首先,为了避免效率问题(不必要的时间损耗),且控制副作用函数(例如发送数据到数据库等),所以我们使用mock语法,直接测试我们的逻辑即可
.only是修饰符代表我们仅执行这个测试用例
axios.get.mockResolvedValue({data: {success: true}});
mock的返回值
然后结合我们的async和await语法,进行测试即可
done
异步函数
import axios from "axios"
// 异步函数
export const axiosData = (fn) => {
axios.get("http://www.dell-lee.com/react/api/demo.json").then((res) => {
fn(res.data)
})
}
测试函数
import {axiosData} from "./asyncFn";
// 使用done
test("axiosData 为", (done) => {
// 回调
axiosData((data) => {
expect(data).toEqual({
success: true,
})
done()
})
})
在这里,我们为什么使用done参数哈,首先如果不使用,其实来说,你的测试异步函数是不是对的就已经不对了,无论如何他都会是无错误的,因为请求发送了!
也就是说,如果不使用done的话,你的请求只要发送了,回调就根本不执行了
而我们写一个done就是让他知道,你必须把done也执行了异步函数才算完成,使用 done() 回调就是来标记测试结束的,这样他就不会提前结束测试了
Jest
其实这些还是有点麻烦了,我们有更好的方式,那就是Jest提供的函数
.resolves 和 .rejects 是不是和promise很像,使用他们两个你的异步函数必须返回一个promise
异步函数
// Jestzidl.js
import axios from "axios";
export async function axiosData() {
const response = await axios.get('https://api.example.com/data');
return response.data;
}
测试函数
import axios from "axios";
import {axiosData} from "./Jestzidl"
// 模拟 axios 请求
jest.mock("axios");
test("", () => {
// 设置模拟的返回数据
axios.get.mockResolvedValue({data: {success: true}});
return expect(axiosData()).resolves.toEqual({success: true});
})
一定不要忘记把整个断言作为返回值返回⸺如果你忘了return语句的话,在 axiosData 返回的这个 promise 变更为 resolved 状态、then() 有机会执行之前,测试就已经被视为已经完成了reject使用方式一致,不在赘述了.
以上就是本期的内容了,如果你有点收获,就请点点赞.
如果有错误,请第一时间和我联系,谢谢,相互进步才有更好的提升呢不是嘛
路很长,有时候,慢也是一种快,加油!