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

Jest Mock实现失效:调用原始数据库函数而非模拟函数

解决Jest Mock数据库addTrip函数失效的问题

问题描述

测试API时尝试Mock数据库的addTrip函数,但实际执行的是原始函数,尽管expect(createTripMock).toHaveBeenCalled()未报错,仍需要实现仅调用模拟函数并返回预设结果,不执行原始逻辑。

核心原因

你的测试代码中,app模块在Mock之前就已经导入,此时app内部已经引用了原始的addTrip函数,后续通过jest.spyOn修改tripDb的addTrip不会影响app里已存在的引用,导致Mock失效。

解决方案

方案1:调整模块导入顺序,先Mock再导入app

将app和supertest的导入放在Mock之后,确保app加载时使用的是Mock后的addTrip函数:

const supertest = require('supertest');
const axios = require('axios');
const querystring = require('querystring');
const DEF = require('../Definition');
const tripDb = require('../database/trip');
const { logger } = require('../Log');

// 先执行Mock操作
const createTripMock = jest.spyOn(tripDb, 'addTrip').mockImplementation(() => Promise.resolve({
  pk: `${companyId}_trip`,
  uid: '1667561135293773',
  lsi1: 'Kotha Yatra',
  lsi2: companyId,
  name: 'Kotha Yatra',
  companyId,
  origin: {
    address: 'Goa, India',
    location: {
      lat: 15.2993265,
      lng: 74.12399599999999,
    },
  },
  destination: {
    address: 'Norway',
    location: {
      lat: 60.47202399999999,
      lng: 8.468945999999999,
    },
  },
  path: [
    {
      lat: 15.2993265,
      lng: 74.12399599999999,
    },
    {
      lat: 60.47202399999999,
      lng: 8.468945999999999,
    },
  ],
  isDeleted: false,
  currentVersion: 1,
  geofences: [],
}));

// 再导入app并创建request实例
const { app } = require('../app');
const request = supertest.agent(app);

describe('trips route test', () => {
  // 剩余测试代码保持不变
});

方案2:使用jest.mock直接Mock整个数据库模块

这种方式更可靠,能确保所有模块引用的都是Mock后的函数:

在测试文件开头添加全局Mock:

jest.mock('../database/trip', () => ({
  addTrip: jest.fn().mockResolvedValue({
    pk: `${companyId}_trip`,
    uid: '1667561135293773',
    lsi1: 'Kotha Yatra',
    lsi2: companyId,
    name: 'Kotha Yatra',
    companyId,
    origin: {
      address: 'Goa, India',
      location: {
        lat: 15.2993265,
        lng: 74.12399599999999,
      },
    },
    destination: {
      address: 'Norway',
      location: {
        lat: 60.47202399999999,
        lng: 8.468945999999999,
      },
    },
    path: [
      {
        lat: 15.2993265,
        lng: 74.12399599999999,
      },
      {
        lat: 60.47202399999999,
        lng: 8.468945999999999,
      },
    ],
    isDeleted: false,
    currentVersion: 1,
    geofences: [],
  })
}));

在测试用例中可随时修改Mock行为或断言调用:

const tripDb = require('../database/trip');

test('post correct data', async (done) => {
  // 如需临时修改返回值
  tripDb.addTrip.mockResolvedValue({ /* 自定义返回数据 */ });

  const response = await request.post('/api/trips')
    .set('Authorization', `Bearer ${token}`)
    .send(tripPayload);
  
  expect(tripDb.addTrip).toHaveBeenCalled();
  expect(response.status).toEqual(200);
  expect(response.body.status).toBe('success');
  done();
});

方案3:测试后清除Mock状态

在每个测试用例结束后重置Mock,避免污染其他测试:

afterEach(() => {
  // 清除所有Mock的调用记录和实例
  jest.clearAllMocks();
});

// 或针对特定Mock重置
afterEach(() => {
  tripDb.addTrip.mockReset();
});

关键注意点

  • Mock操作必须发生在所有依赖该模块的其他模块(如app)导入之前,否则已加载的模块会保留原始函数引用。
  • jest.mock比jest.spyOn更适合全局Mock模块,能彻底避免导入顺序问题。

内容的提问来源于stack exchange,提问作者Prasanth Perli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 17:30:51