You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何jest.spyOn未调用mockImplementation却篡改原函数实现?

Jest spyOn Prisma方法时默认返回undefined的原因及解决办法

为什么会出现这个问题?

核心原因是Prisma Client的模型方法(比如findFirst)不是普通JS函数,而是通过Proxy代理生成的动态方法,和jest.spyOn处理普通对象函数的逻辑完全不同:

  • 对普通对象的方法,jest.spyOn(foo, 'bar')会包装原函数,保留其原有实现,只做调用记录,不会影响功能。
  • 但Prisma的方法是运行时动态生成的,jest.spyOn无法正确捕获到原函数的引用,会直接将该方法替换成一个空的mock函数(和jest.fn()效果一致),自然返回undefined。

不用describe+beforeEach/afterEach的解决办法

不用嵌套测试块也能确保方法被恢复,关键是用finally块强制执行恢复操作——不管测试断言成功还是失败,finally里的代码都会运行:

test('测试Prisma findFirst调用', () => {
  // 先保存原方法的引用(双重保险)
  const originalFindFirst = prismaConnection.event.findFirst;
  // 创建spy
  const findFirstSpy = jest.spyOn(prismaConnection.event, 'findFirst');

  try {
    // 你的测试逻辑:调用相关业务代码,触发findFirst
    // ...

    // 断言spy的调用情况
    expect(findFirstSpy).toHaveBeenCalledWith(/* 预期参数 */);
  } finally {
    // 强制恢复原方法
    findFirstSpy.mockRestore();
    // 万一mockRestore失效,直接赋值回原方法
    prismaConnection.event.findFirst = originalFindFirst;
  }
});

另外,如果你只需要在当前测试中mock一次实现,也可以用mockImplementationOnce,它会在调用一次后自动恢复原实现:

const findFirstSpy = jest.spyOn(prismaConnection.event, 'findFirst')
  .mockImplementationOnce(() => Promise.resolve(/* 你的模拟返回值 */));

补充说明

Prisma的Proxy特性导致其客户端方法和常规JS函数的测试行为存在差异,直接用jest.spyOn会出现兼容性问题。如果频繁遇到这类场景,也可以考虑使用Prisma官方提供的测试工具@prisma/client/testing,但单一场景下,上述的finally恢复方式足够解决问题。

内容的提问来源于stack exchange,提问作者Francisco Barros

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 23:15:15