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

Jest单元测试:如何对函数内部嵌套函数设置Mock响应

嘿,我刚好处理过类似的Mock场景!要给这个返回Promise的高阶函数里的嵌套依赖做Mock,用Jest(Node.js最常用的测试框架)就能轻松实现,我给你一步步拆解:

如何Mock Cassandra驱动模块中的嵌套函数

首先先把你的目标模块代码补全(方便大家理解逻辑):

// cassandraDriver.js
const driver = require('cassandra-driver');
// 假设authProvider是外部模块或者内部嵌套函数
const authProvider = require('./auth-provider'); 

module.exports = ({ cassandra_user, cassandra_password, cassandra_address }) => {
  if (!cassandra_address.length) throw Error('Cassandra address is not valid');
  
  return new Promise((resolve, reject) => {
    try {
      const client = new driver.Client({
        contactPoints: cassandra_address.split(','),
        authProvider: authProvider(cassandra_user, cassandra_password)
      });
      // 假设这里执行client.connect()并返回结果
      client.connect()
        .then(() => resolve(client))
        .catch(err => reject(err));
    } catch (err) {
      reject(err);
    }
  });
};

方案1:Mock外部依赖(比如cassandra-driver和authProvider)

如果authProvider是外部模块,我们可以直接Mock整个依赖包:

// cassandraDriver.test.js
const cassandraDriver = require('./cassandraDriver');
const driver = require('cassandra-driver');

// Mock cassandra-driver的Client类,以及它的connect方法
jest.mock('cassandra-driver', () => {
  // 先Mock connect方法,让它返回成功的Promise
  const mockConnect = jest.fn().mockResolvedValue(true);
  return {
    Client: jest.fn().mockImplementation(() => ({
      connect: mockConnect
    }))
  };
});

// 再Mock authProvider模块,让它返回一个固定的mock值
jest.mock('./auth-provider', () => jest.fn().mockReturnValue('mock-auth-instance'));

test('should resolve with client when config is valid', async () => {
  const testConfig = {
    cassandra_user: 'test-user',
    cassandra_password: 'test-pass',
    cassandra_address: '127.0.0.1,127.0.0.2'
  };
  
  const clientInstance = await cassandraDriver(testConfig);
  
  // 验证Client是否被正确实例化,参数是否符合预期
  expect(driver.Client).toHaveBeenCalledWith({
    contactPoints: ['127.0.0.1', '127.0.0.2'],
    authProvider: 'mock-auth-instance'
  });
  // 验证connect方法是否被调用
  expect(clientInstance.connect).toHaveBeenCalled();
});

test('should throw error when cassandra_address is empty', () => {
  const invalidConfig = {
    cassandra_user: 'test-user',
    cassandra_password: 'test-pass',
    cassandra_address: ''
  };
  
  expect(() => cassandraDriver(invalidConfig)).toThrow('Cassandra address is not valid');
});

方案2:Mock内部嵌套的authProvider函数

如果authProvider是cassandraDriver.js内部的私有函数,我们可以先把它导出(方便测试),再用jest.spyOn来Mock:

第一步:修改原模块,导出内部函数

// cassandraDriver.js
const driver = require('cassandra-driver');

// 内部嵌套的authProvider函数
const authProvider = (user, pass) => {
  return new driver.auth.PlainTextAuthProvider(user, pass);
};

// 导出这个函数,仅用于测试
module.exports.authProvider = authProvider;

// 原有的主导出函数
module.exports = ({ cassandra_user, cassandra_password, cassandra_address }) => {
  // ... 原有逻辑不变 ...
};

第二步:在测试中Mock内部函数

// cassandraDriver.test.js
const cassandraDriver = require('./cassandraDriver');
const driver = require('cassandra-driver');

// 先Mock cassandra-driver的相关类
jest.mock('cassandra-driver', () => ({
  Client: jest.fn().mockImplementation(() => ({ connect: jest.fn().mockResolvedValue(true) })),
  auth: {
    PlainTextAuthProvider: jest.fn()
  }
}));

test('should use authProvider with correct credentials', async () => {
  // 用spyOn来Mock内部的authProvider函数
  const mockAuth = jest.spyOn(cassandraDriver, 'authProvider').mockReturnValue('mock-auth');
  
  const testConfig = {
    cassandra_user: 'test-user',
    cassandra_password: 'test-pass',
    cassandra_address: '127.0.0.1'
  };
  
  await cassandraDriver(testConfig);
  
  // 验证authProvider是否被传入正确的参数
  expect(mockAuth).toHaveBeenCalledWith('test-user', 'test-pass');
  // 验证Client实例化时用了mock的authProvider
  expect(driver.Client).toHaveBeenCalledWith(expect.objectContaining({
    authProvider: 'mock-auth'
  }));
  
  // 测试结束后恢复原函数,避免影响其他测试
  mockAuth.mockRestore();
});

几个关键提示

  • 如果你用的是Sinon而不是Jest,思路完全一致:用sinon.stub()替换目标依赖,设置返回值或行为即可。
  • 测试错误场景时,别忘了用await expect(cassandraDriver(invalidConfig)).rejects.toThrow(...)来验证Promise的reject情况。
  • 一定要验证依赖的调用参数,而不只是测试返回结果,这样才能确保你的函数逻辑是符合预期的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:39:46