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

如何使用Sinon对oracledb进行Stub?单元测试场景求助

如何用Sinon Stub OracleDB的conn.execute方法做单元测试

我明白你的困扰——因为conn是在getDataFromOracleDB函数内部通过oracledb.getConnection动态创建的,直接去stub一个不存在的本地conn实例肯定行不通。核心思路是:先mockoracledb.getConnection的返回值,让它返回一个我们预先控制的模拟连接对象,再在这个对象上stubexecute方法。

下面是具体的实现步骤和代码示例(以Mocha+Sinon+Chai的测试组合为例):

步骤拆解

  1. 模拟连接对象:创建一个包含execute方法的mock对象,后续我们会对这个方法做stub。
  2. Stuboracledb.getConnection:让它返回一个Promise,resolve到我们的模拟连接对象。
  3. 配置execute的返回值:根据测试场景,设置stub的成功/失败返回结果。
  4. 执行测试并断言:验证函数行为是否符合预期,比如方法调用次数、参数、返回值等。

完整测试代码示例

const sinon = require('sinon');
const oracledb = require('oracledb');
const { expect } = require('chai');
const { getDataFromOracleDB } = require('./your-module-path'); // 替换为你的函数所在模块路径
const dbConfig = require('./db-config'); // 你的数据库配置文件

describe('getDataFromOracleDB', () => {
  let getConnectionStub;
  let executeStub;
  let mockConn;

  // 每个测试前初始化stub
  beforeEach(() => {
    // 1. 创建模拟的数据库连接对象,包含需要stub的execute和close方法(如果你的函数里有close操作)
    mockConn = {
      execute: sinon.stub(),
      close: sinon.stub().resolves() // 模拟连接关闭成功,避免函数里的finally块报错
    };

    // 2. Stub oracledb.getConnection,让它返回我们的模拟连接
    getConnectionStub = sinon.stub(oracledb, 'getConnection');
    getConnectionStub.resolves(mockConn);

    // 3. 设置execute的默认返回值,模拟数据库查询结果
    executeStub = mockConn.execute;
    executeStub.resolves({
      rows: [['user1', '25'], ['user2', '30']] // 这里替换为你期望的测试数据
    });
  });

  // 每个测试后恢复所有stub,避免影响其他测试用例
  afterEach(() => {
    sinon.restore();
  });

  it('应该成功从Oracle数据库获取数据', async () => {
    const testFilter = 'active';
    const testQuery = 'SELECT name, age FROM users WHERE status = :1';

    // 调用目标函数
    const result = await getDataFromOracleDB(testFilter, testQuery);

    // 断言getConnection被正确调用
    sinon.assert.calledOnce(getConnectionStub);
    sinon.assert.calledWith(getConnectionStub, dbConfig);

    // 断言execute被正确调用
    sinon.assert.calledOnce(executeStub);
    sinon.assert.calledWith(executeStub, testQuery, [testFilter]);

    // 断言返回结果符合预期
    expect(result).to.deep.equal([['user1', '25'], ['user2', '30']]);
  });

  it('数据库连接失败时应该抛出错误', async () => {
    // 修改stub,模拟连接失败场景
    getConnectionStub.rejects(new Error('无法连接到数据库'));

    await expect(getDataFromOracleDB('test', 'SELECT * FROM users'))
      .to.be.rejectedWith('无法连接到数据库');
  });

  it('查询执行失败时应该抛出错误', async () => {
    // 修改execute stub,模拟查询失败场景
    executeStub.rejects(new Error('SQL语法错误'));

    await expect(getDataFromOracleDB('test', 'SELECT * FROM users'))
      .to.be.rejectedWith('SQL语法错误');
  });
});

关键注意点

  • 如果你原函数里有在finally块调用conn.close()的逻辑,一定要给模拟连接对象添加close方法的stub,否则测试会报错。
  • 使用sinon.stub().resolves()/rejects()来模拟异步操作的成功或失败,这和原函数的Promise逻辑匹配。
  • 测试后用sinon.restore()恢复所有被stub的方法,保证每个测试用例的独立性。

内容的提问来源于stack exchange,提问作者Tso Liang Wu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 11:10:23