如何使用Sinon对oracledb进行Stub?单元测试场景求助
如何用Sinon Stub OracleDB的
conn.execute方法做单元测试 我明白你的困扰——因为conn是在getDataFromOracleDB函数内部通过oracledb.getConnection动态创建的,直接去stub一个不存在的本地conn实例肯定行不通。核心思路是:先mockoracledb.getConnection的返回值,让它返回一个我们预先控制的模拟连接对象,再在这个对象上stubexecute方法。
下面是具体的实现步骤和代码示例(以Mocha+Sinon+Chai的测试组合为例):
步骤拆解
- 模拟连接对象:创建一个包含
execute方法的mock对象,后续我们会对这个方法做stub。 - Stub
oracledb.getConnection:让它返回一个Promise,resolve到我们的模拟连接对象。 - 配置
execute的返回值:根据测试场景,设置stub的成功/失败返回结果。 - 执行测试并断言:验证函数行为是否符合预期,比如方法调用次数、参数、返回值等。
完整测试代码示例
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
相关产品推荐
相关产品推荐

