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

如何用Sinon Mock Knex查询?转换测试遇属性不存在错误

解决Knex查询函数Mock时的"Cannot stub non-existent own property"错误

看起来你遇到的问题核心是:getDataById并非某个对象的自有可Stub属性——要么它是直接导出的独立函数,要么你的导入/Stub方式不对,导致Sinon找不到可操作的目标。结合你的原有测试代码,我给你几种可行的解决方案:

方案1:用Proxyquire替换模块导出(推荐)

如果getDataById是单独导出的(比如module.exports = getDataById),或是属于某个模块的导出对象,Proxyquire可以帮你在测试时无缝替换掉这个函数的实现,完美避开Stub非自有属性的问题。

示例代码:

const proxyquire = require('proxyquire');
const sinon = require('sinon');
const { expect } = require('chai');

describe('Data Get', () => {
  let getDataByIdStub;
  let dataService;

  before(() => {
    // 创建Stub并预设返回的测试数据
    getDataByIdStub = sinon.stub().resolves(yourMockData);
    // 用Proxyquire加载目标模块,替换掉getDataById
    // 假设你的getDataById在./data-service.js中,根据导出方式调整:
    // 情况1:默认导出函数 → './data-service': getDataByIdStub
    // 情况2:导出对象 → './data-service': { getDataById: getDataByIdStub }
    dataService = proxyquire('./data-service', {
      './data-service': getDataByIdStub
    });
  });

  it('Should return correct data for valid ID', async () => {
    const result = await dataService.getDataById({ id: validId });
    expect(result).to.deep.equal(expectedData);
    // 验证Stub被正确调用
    sinon.assert.calledWith(getDataByIdStub, { id: validId });
  });
});

方案2:直接Stub模块导出对象(对象导出场景)

如果getDataById是作为对象的方法导出的(比如module.exports = { getDataById }),你可以直接Stub这个导出对象上的方法,前提是测试中导入的是这个对象:

示例代码:

const sinon = require('sinon');
const { expect } = require('chai');
const dataService = require('./data-service');

describe('Data Get', () => {
  let getDataByIdStub;

  before(() => {
    // 直接Stub导出对象上的getDataById方法
    getDataByIdStub = sinon.stub(dataService, 'getDataById').resolves(yourMockData);
  });

  after(() => {
    // 测试结束后恢复原方法
    dataService.getDataById.restore();
  });

  it('Should return correct data for valid ID', async () => {
    const result = await dataService.getDataById({ id: validId });
    expect(result).to.deep.equal(expectedData);
    sinon.assert.calledWith(getDataByIdStub, { id: validId });
  });
});

方案3:Mock Knex查询链(验证查询逻辑)

如果你想验证Knex查询的正确性(比如表名、字段、查询条件是否符合预期),可以直接Mock Knex的链式调用:

示例代码:

const sinon = require('sinon');
const { expect } = require('chai');
const knex = require('./your-knex-instance');
const dataService = require('./data-service');

describe('Data Get', () => {
  let knexFromStub;
  let selectStub;
  let whereStub;

  before(() => {
    // 构建Knex查询链的Stub
    whereStub = sinon.stub().resolves(yourMockData);
    selectStub = sinon.stub().returns({ where: whereStub });
    knexFromStub = sinon.stub(knex, 'from').returns({ select: selectStub });
  });

  after(() => {
    // 恢复Knex原方法
    knex.from.restore();
  });

  it('Should build correct Knex query and return data', async () => {
    const result = await dataService.getDataById({ id: validId });
    expect(result).to.deep.equal(expectedData);
    // 验证查询链的参数是否正确
    sinon.assert.calledWith(knexFromStub, 'data');
    sinon.assert.calledWith(selectStub, ['a AS A', 'b as B']);
    sinon.assert.calledWith(whereStub, 'id', validId);
  });
});

为什么会出现这个报错?

你之前的代码是Stubconn.executeQuery——这是一个明确的对象自有属性方法,Sinon可以直接识别操作。但现在你尝试Stub的getDataById要么是独立导出的函数(不属于任何对象的属性),要么导入方式错误(比如直接导入函数本身而非包含它的对象),导致Sinon无法将其识别为可Stub的目标。

你可以根据测试需求选择方案:

  • 只想验证业务逻辑 → 方案1/2更简单高效;
  • 要验证Knex查询的正确性 → 方案3更贴合真实调用场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:41:48