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

如何为node_redis的setExp函数编写正确的Mocha测试用例?

解决node_redis异步函数Mocha测试的错误场景问题

首先得指出你当前代码和测试用例里的几个核心问题:

  1. 你的setExp是异步函数,但没有对外暴露回调参数,导致测试根本无法捕获Redis操作的错误或结果;
  2. 测试用例是同步写法,直接调用setExp后立刻断言,完全没等待异步操作完成;
  3. 直接连接真实Redis服务很难构造预期的错误场景,需要用Mock/Stub模拟Redis客户端的行为。

下面一步步给出修正方案:


第一步:修正cache.js的setExp函数

给函数添加回调参数,把Redis操作的错误和结果传递出去:

var redis = require('redis'); // 你原来的代码里应该有这句,补上
var redisCache = redis.createClient(port, name); 
redisCache.on("error", function(err) { 
  logger.error("Error connecting to redis", err); 
}); 

// 添加callback参数,用于传递异步操作的错误/结果
exports.setExp = function(key, timeLeft, data, callback){ 
  redisCache.set(key, JSON.stringify(data), function (err, reply) { 
    if(err) { 
      logger.info("This errror on set key related to node_redis");
      return callback(err); // 把SET错误传递给调用者
    } 
    if(reply === 'OK') { 
      redisCache.expire(key, timeLeft, function (err, reply) { 
        if(err) { 
          logger.info("This errror on expire key related to node_redis");
          return callback(err); // 把EXPIRE错误传递给调用者
        } 
        if(reply === 1) { 
          logger.info(`${key} key expire time set as ${timeLeft} successfully!`);
          callback(null, reply); // 成功时传递结果
        }
      }); 
    } 
  }); 
}

第二步:编写正确的Mocha测试用例

我们用sinon(用于Stub方法)和rewire(用于访问模块私有变量)来模拟Redis客户端的行为,不需要真实Redis服务就能构造错误场景。

先安装依赖:

npm install mocha sinon rewire --save-dev

测试用例代码:

var assert = require('assert');
var rewire = require('rewire');
var sinon = require('sinon');
// 用rewire加载cache模块,方便访问私有变量redisCache
var cache = rewire('../cache');

describe('cache', function () {
  let redisCacheStub;
  let setStub;
  let expireStub;

  // 每个测试前,Stub Redis客户端的set/expire方法
  beforeEach(function() {
    redisCacheStub = cache.__get__('redisCache');
    setStub = sinon.stub(redisCacheStub, 'set');
    expireStub = sinon.stub(redisCacheStub, 'expire');
  });

  // 每个测试后恢复原方法,避免影响其他测试
  afterEach(function() {
    setStub.restore();
    expireStub.restore();
  });

  it('should return SET command error when key is undefined', function (done) {
    // 构造预期的错误对象
    const testError = { command: 'SET', code: 'ERR' };
    // 模拟set方法调用时返回错误
    setStub.callsArgWith(2, testError, null);

    // 调用setExp并传入回调,在回调里断言
    cache.setExp(undefined, 0, [], function(err) {
      assert.equal(err.command, 'SET');
      done(); // 告诉Mocha异步操作完成
    });
  });

  it('should return "ERR wrong number of arguments for \'set\' command" error', function (done) {
    const testError = new Error('ERR wrong number of arguments for \'set\' command');
    setStub.callsArgWith(2, testError, null);

    cache.setExp('foo', 10, [], function(err) {
      assert.equal(err.message, 'ERR wrong number of arguments for \'set\' command');
      done();
    });
  });

  it('should set expire time successfully with valid arguments', function (done) {
    // 模拟set返回OK,expire返回1(表示成功设置过期时间)
    setStub.callsArgWith(2, null, 'OK');
    expireStub.callsArgWith(2, null, 1);

    cache.setExp('test-key', 60, { content: 'test data' }, function(err, reply) {
      assert.isNull(err);
      assert.equal(reply, 1);
      done();
    });
  });
});

关键说明

  • 异步函数必须暴露回调:Redis操作都是异步的,你必须通过回调(或Promise)把结果/错误传递给调用者,否则测试无法捕获异步操作的状态;
  • 用Stub模拟Redis行为:直接连接真实Redis很难稳定构造错误场景,用sinon Stub Redis的方法,可以完全控制它返回的错误或结果;
  • 异步测试的正确姿势:Mocha测试异步代码时,必须调用done()回调,或者返回Promise,确保测试等待异步操作完成后再执行断言。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:43:25