Node.js/TypeScript中Jest无法mock类构造函数问题求解
Jest mock @azure/identity 中 ClientSecretCredential 构造函数不生效的解决方案
核心问题原因
你的代码存在三个直接导致mock失效、断言不命中的问题:
jest.mock位置错误:Jest会自动将所有jest.mock调用提升到文件最顶部、import语句之前执行,你把它嵌套在describe块内部,会导致mock覆盖逻辑无法正确绑定到导入的ClientSecretCredential引用上。- 断言逻辑错误:构造函数实例化时抛出错误是同步行为,
.rejects仅用于捕获Promise异步拒绝场景,用在这里永远无法命中同步抛出的错误。 - mock逻辑未做入参匹配:你需要根据传入的三个入参(tenantId、clientId、clientSecret)判断抛出对应异常,无法自动根据参数区分错误类型。
正确实现代码
import { ClientSecretCredential } from "@azure/identity"; // jest.mock必须放在文件顶层,Jest会自动提升到import前执行 jest.mock("@azure/identity", () => ({ ClientSecretCredential: jest.fn() })); describe("ClientSecretCredential described", () => { beforeEach(() => { jest.clearAllMocks(); }); describe("Azure identity", () => { it("Should throw an error on incorrectly provided tenantId, clientId or clientSecret", () => { // 动态设置mock构造函数实现,根据入参抛出对应错误 (ClientSecretCredential as jest.Mock).mockImplementation( (tenantId: string, clientId: string, clientSecret: string) => { if (tenantId !== "valid_tenant_id") { throw new Error("Invalid tenant id is provided"); } if (clientId !== "valid_client_id") { throw new Error("Invalid client id is provided"); } if (clientSecret !== "valid_client_secret") { throw new Error("Invalid client secret is provided"); } // 正常实例化场景返回符合类型的mock对象即可 return {} as ClientSecretCredential; } ); // 同步抛错不需要加.rejects,直接包裹实例化逻辑断言抛出内容 expect(() => new ClientSecretCredential("some id", "some id", "some id")) .toThrowError("Invalid tenant id"); }); }); });
优化提示
- TypeScript项目中可以用
jest.mocked(ClientSecretCredential)获取带完整类型提示的mock对象,省去手动类型断言的步骤:const MockedClientSecretCredential = jest.mocked(ClientSecretCredential); // 后续直接调用MockedClientSecretCredential.mockImplementation即可,无类型报错 - 不需要在
jest.mock初始化时写死mock实现,只需要在顶层将目标类替换为jest.fn(),可以在不同测试用例、beforeEach钩子中动态设置不同的实现逻辑,适配不同测试场景。 - 禁止在describe/it块内部声明
jest.mock,除了作用域提升问题外,还容易触发模块缓存异常导致mock偶发不生效。
内容的提问来源于stack exchange,提问作者Igor Lopatchin
相关产品推荐
相关产品推荐

