我是 Jest 新手,正在尝试对一些现有代码编写一些测试。虽然我遇到过很多关于模块内模拟函数的 Jest 文章和 Stackoverflow 帖子(例如this),但我相信我正在尝试实现一些有点先进或非常愚蠢的东西,并且需要代码重构。不管怎样,我不确定,并且非常感谢一些帮助!
\n让我使用示例代码来解释我的情况。假设我们正在处理一个电子商务系统,后端有一个模块可以从某些 API 获取订单详细信息:
\n// get-order-data.js\n\nconst getOrderDataFromApi = async (orderId) => {\n // . . . some API call\n console.log("The actual getOrderData function called!");\n}\n\n// Added only to emphasize that the entire module shouldn\'t be mocked\nconst getOrderDataFromDatabase = async (orderId) => { }\n\nmodule.exports = {\n getOrderDataFromApi,\n getOrderDataFromDatabase,\n}\nRun Code Online (Sandbox Code Playgroud)\n还有一个非常相似的模块,用于获取订单的交付数据:
\n// get-delivery-data.js\n\nconst getDeliveryDataFromApi = async (orderId) => {\n // . . . some API call\n console.log("The actual getDeliveryDataFromApi function called!");\n}\n\n// Added only to emphasize that the entire module shouldn\'t be mocked\nconst getDeliveryDataFromDatabase = async (orderId) => { }\n\nmodule.exports = {\n getDeliveryDataFromApi,\n getDeliveryDataFromDatabase,\n}\nRun Code Online (Sandbox Code Playgroud)\n可以看到,console.log每个模块中都有一个,用于指示已经执行了原始代码而不是模拟代码。
现在,假设这两个模块都被另一个模块函数使用,如下所示:
\n// combine-order-data.js\nconst { getDeliveryDataFromApi } = require("./get-delivery-data");\nconst { getOrderDataFromApi } = require("./get-order-data")\n\nconst combineOrderData = async (orderId) => {\n const orderData = await getOrderDataFromApi(orderId);\n const deliveryData = await getDeliveryDataFromApi(orderId);\n\n return {\n orderData,\n deliveryData,\n };\n}\n\nmodule.exports = {\n combineOrderData,\n};\nRun Code Online (Sandbox Code Playgroud)\ncombineOrderData()我想通过模拟getOrderDataFromApi()和来测试这个函数的行为getDeliveryDataFromApi()。
为此,我创建了以下测试文件:
\n// order.test.js\n\nconst { combineOrderData } = require("./combine-order-data");\n\nconst mockedOrderData = {\n id: 1,\n amount: 1000,\n};\n\nconst mockedDelieryData = {\n orderId: 1,\n status: \'DELIVERED\',\n};\n\nbeforeEach(() => {\n jest.mock("./get-order-data", () => {\n getOrderDataFromApi: jest.fn(() => Promise.resolve(mockedOrderData))\n });\n jest.mock("./get-delivery-data", () => {\n getDeliveryDataFromApi: jest.fn(() => Promise.resolve(mockedDelieryData))\n });\n});\n\ntest("combineOrderData correctly combines data", async () => {\n const combinedOrder = await combineOrderData(111);\n});\nRun Code Online (Sandbox Code Playgroud)\n当我现在运行时npx jest,我console.log在输出中看到 s,告诉我模拟没有成功:
console.log\n The actual getOrderData function called!\n\n at getOrderDataFromApi (get-order-data.js:3:13)\n\n console.log\n The actual getDeliveryDataFromApi function called!\n\n at getDeliveryDataFromApi (get-delivery-data.js:3:13)\n\n PASS ./order.test.js\n \xe2\x9c\x93 combineOrderData correctly combines data (28 ms)\n\nTest Suites: 1 passed, 1 total\nTests: 1 passed, 1 total\nSnapshots: 0 total\nTime: 0.227 s\nRan all test suites related to changed files.\nRun Code Online (Sandbox Code Playgroud)\n我认为发生这种情况是因为当combineOrderData()被调用时,它会实例化自己所使用的模块的副本(我认为 Node 模块默认情况下是单例的;例如,只有导入模块的一份副本存在并由所有require模块共享)?
无论如何,我不知道实现这一目标的正确方法是什么。
\n另外,如果代码结构被破坏并且重构可以解决问题,请随时发表评论,但我不知道如何避免编写和测试进行其他函数调用的代码,所以看来我会遇到这个问题定期出现问题。
\n小智 5
我发现测试有 2 个问题
jest.mock("./get-delivery-data", () => ({
getDeliveryDataFromApi: jest.fn(() => Promise.resolve(mockedDelieryData)),
}));
Run Code Online (Sandbox Code Playgroud)
首先require导入实际模块而不是模拟模块。
工作测试
jest.mock("./get-order-data", () => ({
getOrderDataFromApi: jest.fn(() => Promise.resolve(mockedOrderData)),
}));
jest.mock("./get-delivery-data", () => ({
getDeliveryDataFromApi: jest.fn(() => Promise.resolve(mockedDelieryData)),
}));
const { combineOrderData } = require("./combine-order-data");
const mockedOrderData = {
id: 1,
amount: 1000,
};
const mockedDelieryData = {
orderId: 1,
status: "DELIVERED",
};
test("combineOrderData correctly combines data", async () => {
const combinedOrder = await combineOrderData(111);
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6913 次 |
| 最近记录: |