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

knex-mock-client单元测试报TypeError: insertLog is not a function

knex-mock-client + Jest TypeScript单测报default is not a function解决

问题场景

相关依赖版本

{
  "@faker-js/faker": "^7.2.0",
  "@types/jest": "^28.1.1",
  "concurrently": "^7.2.1",
  "jest": "^28.1.1",
  "knex-mock-client": "^1.8.4",
  "nodemon": "^2.0.16",
  "ts-jest": "^28.0.4"
}

业务代码(insertRecord.ts)

//insertRecord.ts
import {knexInstance} from './logDatabaseConfig';

const insertLog = async(quan: Number) => {
    try {
        await knexInstance('LOG')
        .insert({sync_quantity: quan, sync_at: new Date()});
    } catch (error) {
    throw new Error('Error insert' + error);
    }  
}

export default insertLog;

原测试代码

import { expect } from '@jest/globals';
import knex, { Knex } from 'knex';
import { Tracker, getTracker, MockClient } from 'knex-mock-client';
import { faker } from '@faker-js/faker';
import insertLog from './insertLog';

// 错误的mock写法
jest.mock('./insertLog', () => {
    return {
      db: knex({ client: MockClient })
    };
});

describe('log insert tests', () => {
    let tracker: Tracker;
  
    beforeAll(() => {
      tracker = getTracker();
    });
  
    afterEach(() => {
      tracker.reset();
    });
  
    it('should add new log record', async () => {
      tracker.on.insert('LOG');
      const syncQuantity = 1;
      await insertLog(1);
  
      const insertHistory = tracker.history.insert;
      expect(insertHistory).toHaveLength(1);
      expect(insertHistory[0].method).toEqual('insert');
    });
});

运行后抛出错误:TypeError: (0 , insertLog_1.default) is not a function,错误定位在await insertLog(1);行。

错误根因

  • mock目标完全错误:单测不能直接mock被测业务模块本身。当前代码把./insertLog整个替换成了只带db属性的对象,原模块默认导出的insertLog函数被完全覆盖,导入后拿到的不是函数,调用必然报错。
  • mock逻辑不符合knex-mock-client使用要求:knex-mock-client需要mock的是导出knex实例的依赖模块(也就是./logDatabaseConfig),替换其中的真实knex连接为MockClient实例,而不是替换业务逻辑模块。
  • 缺失mock响应配置:原测试中tracker.on.insert('LOG')没有设置返回值,knex mock调用会返回undefined,容易触发业务代码异常分支。

修复方案

  1. 修改mock路径,指向knex实例所在的./logDatabaseConfig模块,不要mock被测的insertLog模块
  2. 让mock返回的对象结构和原模块导出结构完全匹配,保证业务代码能正常拿到mock的knex实例
  3. 给tracker监听的insert操作设置mock响应值,避免await拿到undefined触发异常

修复后测试代码

import { expect } from '@jest/globals';
import knex from 'knex';
import { Tracker, getTracker, MockClient } from 'knex-mock-client';
import insertLog from './insertLog';

// 正确mock:替换knex配置模块中的真实实例为mock客户端
jest.mock('./logDatabaseConfig', () => {
  const mockKnexInstance = knex({ client: MockClient });
  return {
    // 匹配原模块的具名导出knexInstance
    knexInstance: mockKnexInstance
  };
});

describe('log insert tests', () => {
  let tracker: Tracker;

  beforeAll(() => {
    tracker = getTracker();
  });

  afterEach(() => {
    tracker.reset();
  });

  it('should add new log record', async () => {
    // 给insert操作设置mock返回值
    tracker.on.insert('LOG').response([]);
    
    const syncQuantity = 1;
    await insertLog(syncQuantity);

    const insertHistory = tracker.history.insert;
    expect(insertHistory).toHaveLength(1);
    expect(insertHistory[0].method).toEqual('insert');
    // 可选:校验插入参数是否符合预期
    expect(insertHistory[0].bindings[0]).toEqual(syncQuantity);
  });
});

排查检查点

  • 单测中jest.mock的目标永远是被测模块依赖的外部/内部依赖模块,不能是被测模块本身,否则测试的是mock逻辑,不是真实业务代码
  • mock返回的对象结构必须和原模块导出结构完全一致:具名导出对应同名属性,ESM默认导出对应default属性
  • 确认tsconfig.json中开启"esModuleInterop": true,避免TS默认导入的取值错误
  • 所有tracker监听的数据库操作都要设置response返回值,避免mock调用返回undefined导致业务逻辑异常

内容的提问来源于stack exchange,提问作者J L

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 23:51:30