我是 Jest 的新手,正尝试在一些现有的代码中编写一些测试。虽然我已经看到很多关于 Jest 和模块内部函数模拟的文章和 Stackoverflow 帖子(例如 this),但我相信我正在尝试完成某些比较高级或非常愚蠢的操作,并需要重构代码。无论哪种情况,我都不确定,真的希望能得到一些帮助!
让我使用一个示例代码来解释我的情况。假设我们正在处理一个电子商务系统,在后端有一个模块从某个 API 获取订单详情:
// get-order-data.js
const getOrderDataFromApi = async (orderId) => {
// . . . some API call
console.log("The actual getOrderData function called!");
}
// Added only to emphasize that the entire module shouldn't be mocked
const getOrderDataFromDatabase = async (orderId) => { }
module.exports = {
getOrderDataFromApi,
getOrderDataFromDatabase,
}
然后还有一个非常类似的模块,用于获取订单的交付数据:
// get-delivery-data.js
const getDeliveryDataFromApi = async (orderId) => {
// . . . some API call
console.log("The actual getDeliveryDataFromApi function called!");
}
// Added only to emphasize that the entire module shouldn't be mocked
const getDeliveryDataFromDatabase = async (orderId) => { }
module.exports = {
getDeliveryDataFromApi,
getDeliveryDataFromDatabase,
}
正如您所看到的,每个模块中都有一个console.log
,用于指示已执行原始代码而不是模拟代码。
现在,假设这两个模块都被另一个模块函数使用,如下所示:
// combine-order-data.js
const { getDeliveryDataFromApi } = require("./get-delivery-data");
const { getOrderDataFromApi } = require("./get-order-data")
const combineOrderData = async (orderId) => {
const orderData = await getOrderDataFromApi(orderId);
const deliveryData = await getDeliveryDataFromApi(orderId);
return {
orderData,
deliveryData,
};
}
module.exports = {
combineOrderData,
};
我想要测试的是combineOrderData()
函数的行为,通过模拟getOrderDataFromApi()
和getDeliveryDataFromApi()
来实现。
为此,我创建了以下测试文件:
// order.test.js
const { combineOrderData } = require("./combine-order-data");
const mockedOrderData = {
id: 1,
amount: 1000,
};
const mockedDelieryData = {
orderId: 1,
status: 'DELIVERED',
};
beforeEach(() => {
jest.mock("./get-order-data", () => {
getOrderDataFromApi: jest.fn(() => Promise.resolve(mockedOrderData))
});
jest.mock("./get-delivery-data", () => {
getDeliveryDataFromApi: jest.fn(() => Promise.resolve(mockedDelieryData))
});
});
test("combineOrderData correctly combines data", async () => {
const combinedOrder = await combineOrderData(111);
});
当我现在运行npx jest
时,我可以在输出中看到console.log
,告诉我模拟没有成功:
console.log
The actual getOrderData function called!
at getOrderDataFromApi (get-order-data.js:3:13)
console.log
The actual getDeliveryDataFromApi function called!
at getDeliveryDataFromApi (get-delivery-data.js:3:13)
PASS ./order.test.js
✓ combineOrderData correctly combines data (28 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.227 s
Ran all test suites related to changed files.
我认为这是因为当调用combineOrderData()
时,它会实例化自己使用的模块的副本(我以为Node模块默认是单例的;也就是说,只有一个导入模块的副本存在,并由所有require
共享)。
无论如何,我不知道实现这一点的正确方法。
此外,请随意评论代码结构是否有问题,重构是否可以解决问题,但我不知道如何避免编写和测试调用其他函数的代码,因此似乎我会经常遇到这个问题。