如何用Jest模拟React Native的Platform.OS及测试静态常量?
React Native Jest测试平台相关静态常量的优化方案
针对你遇到的静态常量在导入阶段就被固化、导致测试无法动态切换平台的问题,除了jest.resetModules()+require的方式,还有以下几种更简便的实现方案:
1. 直接Mock依赖的静态常量
既然items模块依赖的是@my/utils导出的isIOS常量,我们可以直接Mock这个常量的值,跳过对Platform的修改,更直接高效:
// 测试文件 it("should be android", () => { // 临时Mock utils模块的isIOS为false jest.mock("@my/utils", () => ({ isIOS: false })); // 重新导入items(避免缓存影响) const { items } = require("./items"); expect(items[0].name).toBe("Android"); }); it("should be ios", () => { jest.mock("@my/utils", () => ({ isIOS: true })); const { items } = require("./items"); expect(items[0].name).toBe("Apple"); });
如果希望isIOS的Mock值和Platform.OS联动,也可以用动态getter:
// 全局Mock utils模块 jest.mock("@my/utils", () => ({ get isIOS() { return jest.requireActual("react-native").Platform.OS === "ios"; }, })); it("should be android", () => { // 仅Mock Platform.OS jest.spyOn(require("react-native").Platform, "OS", "get").mockReturnValue("android"); const { items } = require("./items"); expect(items[0].name).toBe("Android"); });
2. 使用jest.isolateModules隔离模块导入
jest.isolateModules会创建一个隔离的模块上下文,自动处理模块缓存的重置,比手动调用jest.resetModules()更简洁:
it("should be android", () => { jest.isolateModules(() => { // 在隔离环境中修改Platform.OS jest.spyOn(require("react-native").Platform, "OS", "get").mockReturnValue("android"); // 导入的模块不会和其他测试用例共享缓存 const { items } = require("./items"); expect(items[0].name).toBe("Android"); }); }); it("should be ios", () => { jest.isolateModules(() => { jest.spyOn(require("react-native").Platform, "OS", "get").mockReturnValue("ios"); const { items } = require("./items"); expect(items[0].name).toBe("Apple"); }); });
3. 重构代码提升可测试性(长期推荐)
从根源解决问题的方式是重构静态常量为可注入的逻辑,让测试更灵活:
修改utils.ts:
import { Platform } from "react-native"; // 将静态常量改为可传入自定义Platform的函数 export const getIsIOS = (platform = Platform) => platform.OS === "ios";
修改items.ts:
import { getIsIOS } from "@my/utils"; // 保留原导出用于业务代码 export const items = [{ id: 1, name: getIsIOS() ? "Apple" : "Android" }]; // 新增带参数的版本用于测试 export const getItems = (platform?: any) => [{ id: 1, name: getIsIOS(platform) ? "Apple" : "Android" }];
测试代码:
import { getItems } from "./items"; it("should be android", () => { const items = getItems({ OS: "android" }); expect(items[0].name).toBe("Android"); }); it("should be ios", () => { const items = getItems({ OS: "ios" }); expect(items[0].name).toBe("Apple"); });
这种方式无需依赖Jest的Mock API,测试逻辑更清晰,也提升了代码的灵活性。
内容的提问来源于stack exchange,提问作者Aure77
相关产品推荐
相关产品推荐

