最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do you stub private functions when unit testing a revealing module - Stack Overflow

programmeradmin2浏览0评论

I have been building a node module that wraps a number of calls to the GitHub API and in my infinite wisdom have built this using the revealing module pattern, keeping my wrapping functions private and only exposing simple methods. See the example below:

github.shortcuts = (function(){

  var appPath;

  var createRepo = function(name){
    var deferred = Q.defer();
    github.repos.create({
      name: name,
      auto_init: true
    }, function(error, result){
      if (error) {
        deferred.reject(new Error(error));
      } else {
        deferred.resolve(result);
      }
    });
    return deferred.promise;
  };

  var updateRef = function(result){
    var deferred = Q.defer();
    var user = result.user;
    var repo = result.repo;
    github.gitdata.updateReference({
      user: user,
      repo: repo,
      ref: 'heads/master',
      sha: result.sha
    }, function(error, result){
      if (error) {
        deferred.reject(new Error(error));
      } else {
        deferred.resolve(result);
      }
    });
    return deferred.promise;
  };

  return {
    init: function(token, name, path){
      var deferred = Q.defer();
      appPath = path;

      var error = function(error){
        return deferred.reject(error);
      };

      github.authenticate({
        type: "oauth",
        token: token
      });

      createRepo(name)
        .then(updateRef, error)
        .then(function(result){
          deferred.resolve(result);
        }, error);

      return deferred.promise;
    }
  };

})();

However writing unit tests for this is causing me issues. I don't want to test my private functions, just the public one init(), however I would want to stub the private functions so that the test will not call to the GitHub API. I am using Mocha and Chai for my tests and Sinon for my spys/stubs.

Any advice on how to stub these functions or if this is a bad pattern, how else I should test this module would be appreciated!

I have been building a node module that wraps a number of calls to the GitHub API and in my infinite wisdom have built this using the revealing module pattern, keeping my wrapping functions private and only exposing simple methods. See the example below:

github.shortcuts = (function(){

  var appPath;

  var createRepo = function(name){
    var deferred = Q.defer();
    github.repos.create({
      name: name,
      auto_init: true
    }, function(error, result){
      if (error) {
        deferred.reject(new Error(error));
      } else {
        deferred.resolve(result);
      }
    });
    return deferred.promise;
  };

  var updateRef = function(result){
    var deferred = Q.defer();
    var user = result.user;
    var repo = result.repo;
    github.gitdata.updateReference({
      user: user,
      repo: repo,
      ref: 'heads/master',
      sha: result.sha
    }, function(error, result){
      if (error) {
        deferred.reject(new Error(error));
      } else {
        deferred.resolve(result);
      }
    });
    return deferred.promise;
  };

  return {
    init: function(token, name, path){
      var deferred = Q.defer();
      appPath = path;

      var error = function(error){
        return deferred.reject(error);
      };

      github.authenticate({
        type: "oauth",
        token: token
      });

      createRepo(name)
        .then(updateRef, error)
        .then(function(result){
          deferred.resolve(result);
        }, error);

      return deferred.promise;
    }
  };

})();

However writing unit tests for this is causing me issues. I don't want to test my private functions, just the public one init(), however I would want to stub the private functions so that the test will not call to the GitHub API. I am using Mocha and Chai for my tests and Sinon for my spys/stubs.

Any advice on how to stub these functions or if this is a bad pattern, how else I should test this module would be appreciated!

Share Improve this question asked Mar 16, 2016 at 17:02 oligibsonoligibson 871 gold badge1 silver badge6 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 9

Actually there are a bunch of very valid reasons that you would want to sub out a private function. Like there is a lot of logic in it and you want to test out just that logic. To stub out any private function stub it out like you would any other function, then attach as any to the parent object:

Spec.ts:

startTimeoutTimerSpy = spyOn(service as any, 'startTimeoutTimer');

service has a private function startTimeoutTimer. Attaching the as any to the service object tells TypeScript to ignore any typings and just assume you can do it.

You should isolate the problematic part of the class and mock that out, rather than stubbing private methods. The need to mock or stub a private method is a design smell, IMO, indicating that the class is too large and you should separate the various concerns.

In this case, you could pass the github API as a parameter to init and, rather than digging through the internals of your class, simply provide a fake API that returns static results.

This is especially helpful when you start testing error cases, as your mock API can throw the appropriate error and allow you to only test the error handling behavior.

Since github looks like a singleton you can override it's functions :

github.gitdata.updateReference = sinon.stub().return(Promise.resolve([]));

And you have to reset it after the test is done :

afterAll(() => {
 github.gitdata.updateReference.reset();
});
发布评论

评论列表(0)

  1. 暂无评论