Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

javascript - Mocking Redis Constructor with Sinon

I'm trying to figure out a way to mock redis in this module:

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
    });
  }
};

Using this test-code:

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');
              });
      });
});

I also tried a few variations, but I'm kind of stuck as I basically need to mock the constructor and I'm not sure Sinon supports this?

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!'));

Not sure what else to try here, I also tried using rewire as suggested here, but using mockRedis.__set__("exists", myMock); never set that private variable.

I want to fake my error paths ultimately.
I would love to hear what others are doing to test redis in node js ??.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your problem is not whether Sinon supports this or that, but rather a missing understanding of how "classes" work in Ecmascript, as shown by the attempt at stubbing constructor property in the test code. That will never work, as that property has nothing to do with how any resulting objects turn out. It is simply a reference to the function that was used to create the object. I have covered a very similar topic on the Sinon tracker that you might have interest in reading to gain some core JS foo :-) Basically, it is not possible to stub a constructor, but you can probably coerce your code to use another constructor function in its place through either DI or link seams.

As a matter of fact, a few answers down in the same thread, you will see me covering an example of how I myself designed a Redis using class to be easily testable by supporting dependency injection. You might want to check it out, as it is more or less directly applicable to your example module above.

Another technique, which you already has tried getting to work, is using link seams (using rewire). The Sinon homepage has a nice article on doing this. Both rewire and proxyquire will do the job just fine here: I think you have just complicated the matter a bit by wrapping the require statement with a mock.

Even though I am on the Sinon maintainer team, I never use the mock functionality, so I cannot tell you how to use that, as I think it obscures the testing, but to get the basic link seams working using rewire I would basically remove all the Sinon code first and get the basic case going (removing redis for a stubbed module you have created).

Only then, add Sinon code as required.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...