使用Sinon模拟Redis构造函数

4

我正在尝试找到一种方式来在这个模块中模拟 Redis:

const Redis  = require('ioredis');
  const myFunction = {
    exists: (thingToCheck) {
      let redis_client = new Redis(
        6379,
        process.env.REDIS_URL,
        {
          connectTimeout: 75,
          dropBufferSupport: true,
          retryStrategy: functionHere
        });

    redis_client.exists(thingToCheck, function (err, resp) {
     // handlings in here
    });
  }
};

使用这个测试代码:
const LambdaTester = require('lambda-tester');
const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');
const mockRedis = sinon.mock(require('ioredis'));

describe( 'A Redis Connection error', function() {
    before(() => {
        mockRedis.expects('constructor').returns({
            exists: (sha, callback) => {
                callback('error!', null);
            }
        });
      });

      it( 'It returns a database error', function() {
          return LambdaTester(lambdaToTest)
              .event(thingToCheck)
              .expectError((err) => {
                   expect(err.message).to.equal('Database error');
              });
      });
});

我也尝试了几个变化,但我有些困惑,因为基本上我需要模拟构造函数,而我不确定Sinon是否支持这个功能?

mockRedis.expects('exists').returns(
  (thing, callback) => {
    callback('error!', null);
  }
);
sinon.stub(mockRedis, 'constructor').callsFake(() => console.log('test!'));
sinon.stub(mockRedis, 'exists').callsFake(() => console.log('test!'));

我在这里不确定还有什么其他的尝试方法,我也试过使用rewire来实现这里建议的方式,但是使用mockRedis.__set__("exists", myMock);从未设置该私有变量。

我想要最终伪造我的错误路径。
我很想听听其他人如何测试node js中的redis。


1
也许你可以看一下ioredis的单元测试,https://github.com/luin/ioredis/blob/master/test/helpers/mock_server.js,在那里你可以看到ioredis如何构建一个假服务器。 - Yu Huang
太棒了,谢谢!我最终只是使用Docker创建了一个本地的Redis服务器,并在错误测试时将其关闭,但当我有更多时间时,我想构建一个更好的模拟。 - cameck
但是上述方法确实很好用,只是希望不必依赖Docker来运行测试。 - cameck
是的,Docker非常适合构建测试数据库。在我的情况下,我通常将应用程序连接到Docker中的Redis集群,但我会截取所有Redis操作。因此,Redis始终为空,但这节省了很多精力。 - Yu Huang
1个回答

1
你的问题不在于Sinon是否支持这个或那个,而是缺乏对Ecmascript中“类”如何工作的理解,正如在测试代码中尝试存根构造函数属性所显示的那样。那永远不会起作用,因为该属性与任何生成的对象的实际结果无关。它只是一个对用于创建对象的函数的引用。我在Sinon跟踪器上涵盖了一个非常相似的主题,你可能有兴趣阅读一些核心JS知识 :-) 基本上,不能存根构造函数,但是您可以通过DI或链接接缝来强制使用另一个构造函数来替换它。
事实上,在同一线程的几个答案中,您将看到我涵盖了一个例子,展示了我自己如何设计Redis使用类以便通过支持依赖注入轻松进行测试。你可能想检查一下,因为它更或多或少直接适用于你上面的示例模块。
另一种你已经尝试过的技术是使用“链接接缝”(使用rewire)。Sinon主页上有一篇关于如何做到这一点的好文章。在这里,rewireproxyquire都可以胜任:我认为你只是通过将require语句包装在一个模拟中使问题变得有些复杂。
虽然我是Sinon维护团队的成员,但我从不使用mock功能,因此我无法告诉你如何使用它,因为我认为它会混淆测试,但是要使用rewire来使基本的链接接缝工作,我会先删除所有Sinon代码并让基本情况正常运行(用你创建的存根模块替换redis)。
只有在需要时才添加Sinon代码。

这非常有用,谢谢!今天学到了一些新东西:D - cameck
很好,如果有人能帮忙那就太棒了。如果你开始并遇到困难,请回复我。如果需要,我可能会更新一些细节。 - oligofren

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接