Mock a class method using mockery and sinon

2019-04-28 22:02发布

I'm learning to unit test using the node module mockery with sinon.

Using only mockery and a plain class I'm able to inject a mock successfully. However I would like to inject a sinon stub instead of a plain class but I'm having a lot of troubles with this.

The class I am trying to mock:

function LdapAuth(options) {}

// The function that I want to mock.
LdapAuth.prototype.authenticate = function (username, password, callback) {}

And here is the code I'm currently using in my beforeEach() function:

    beforeEach(function() {
        ldapAuthMock = sinon.stub(LdapAuth.prototype, "authenticate", function(username, password, callback) {});
        mockery.registerMock('ldapauth-fork', ldapAuthMock);
        mockery.enable();
    });

    afterEach(function () {
        ldapAuthMock.restore();
        mockery.disable();
    });

I've tried to mock/stub the LdapAuth class in various ways without success and the code above is just the latest version that doesn't work.

So I just want to know how to mock this successfully using sinon and mockery.

1条回答
叛逆
2楼-- · 2019-04-28 22:41

These node mocking libraries can be quite cumbersome because of Node's module cache, Javascript's dynamic nature and it's prototypical inheritance.

Fortunately Sinon also takes care of modifying the object you are trying to mock as well as providing a nice API to construct spys, subs and mocks.

Here is a small example of how I would stub the authenticate method:

// ldap-auth.js

function LdapAuth(options) {
}

LdapAuth.prototype.authenticate = function (username, password, callback) {
  callback(null, 'original');
}

module.exports = LdapAuth;
// test.js

var sinon = require('sinon');
var assert = require('assert');
var LdapAuth = require('./ldap-auth');

describe('LdapAuth#authenticate(..)', function () {
  beforeEach(function() {
    this.authenticateStub = sinon
                              // Replace the authenticate function
                              .stub(LdapAuth.prototype, 'authenticate')
                              // Make it invoke the callback with (null, 'stub')
                              .yields(null, 'stub');
  });

  it('should invoke the stubbed function', function (done) {
    var ldap = new LdapAuth();
    ldap.authenticate('user', 'pass', function (error, value) {
      assert.ifError(error);
      // Make sure the "returned" value is from our stub function
      assert.equal(value, 'stub');
      // Call done because we are testing an asynchronous function
      done();
    });
    // You can also use some of Sinon's functions to verify that the stub was in fact invoked
    assert(this.authenticateStub.calledWith('user', 'pass'));
  });

  afterEach(function () {
    this.authenticateStub.restore();
  });
});

I hope this helps.

查看更多
登录 后发表回答