How many times have you tried to follow good programming practices by creating well-defined, single-purposed methods and only exposing the necessary public methods outside of your library and become frustrated with attempting to write unit tests for your code? You then begin to question your decisions about which method(s) should be `public` and which methods should be `private`. Additionally, you start to wonder if 100% code coverage is truly necessary. I mean, 75% of code coverage isn’t really that bad, is it? It’s better than 10%, right?

If you scour the web for suggestions, there’s a number of less-than-optimal solutions for this problem. First, I’d like to cover some of these solutions and why they are less than ideal. Second, I’ll provide some production code that contains a private method along with how to successfully achieve 100% coverage with unit tests. The examples provided are in Node.js.

First, let’s consider the following code:

module.exports = {
    myPubFunc: async function() {
        let val = await myPrivFunc();

        // do something (perhaps, call 'myPrivFunc' again, if necessary);

        return true;
    }
}

function myPrivFunc() {
    return new Promise((resolve, reject) => {
        // if something is successful or true, 'resolve', otherwise, 'reject'
    });
}

Don’t worry about the purpose of myPrivFunc as it’s not really important. The primary issue at hand is that myPrivFunc has logic in it that has a single purpose and can be used many times within – and should only be within – the exported module. Creating the private function increases readability and manageability while reducing complexity, code-bloat and code reproduction. I’ve seen many arguments lately for there being no need for private methods, but no one yet has provided an adequate reason.

AntiPatterns for Private Methods

There’s a number of bad solutions for the problem of private methods. Again, before I show you how to correctly unit test with private methods, I want to cover what not to do. All of these ‘solutions’ (and I use that term very lightly) are suggested in a number of blogs across the web. But, before you follow one of these practices, remember why you made your method(s) private in the first place. There are a number of great reasons why you would use access modifiers (e.g. private, internal, protected, etc.) other than public – even though the modifiers themselves may not explicitly be used in some languages (like JavaScript), but are implied through code.

Referencing the code above, I’ll give some examples of AntiPatterns and explain why they are bad solutions for the problem at hand.

No Private Functions

Yes. There are actually people who advocate making all functions public in the name of unit testing. I cannot facepalm loud enough. If you follow SOLID design principles where each function has a single purpose, then good, controlled integration tests are more than adequate to test private functions.

‘Hidden’ Properties

Consider the following rewrite of the above module:

module.exports = {
    myPubFunc: async function() {
        let val = await myPrivFunc();

        // do something (perhaps, call 'myPrivFunc' again, if necessary);

        return true;
    },

    __private__ : {
        myPrivFunc: myPrivFunc
    }
}

This will expose the private function myPrivFunc through a ‘private’ property of the exported module. By making the private property public through a public property called __private__ (did you follow that?), this would allow you to possibly stub out the private function. However, the property isn’t really private as IntelliSense (or any code completion assistant) will still display the property.

PrivateProperty

Thus, what’s the point? As now, you’ve basically exposed your private function and defeated the purpose of making it private to begin with.

Dependent Module

Consider this rewrite of the module:

var private = require('./private');

module.exports = {
    myPubFunc: async function() {
        let val = await private.myPrivFunc();

        // do something (perhaps, call 'myPrivFunc' again, if necessary);

        return true;
    }
}

Again, this would allow you to stub your private function, but your private function is now a public function in another module. And, there’s nothing to prevent other users from inadvertently calling your private method directly. This can often be hazardous in production environments (again, there’s a reason methods are private). Naming conventions, at this point, can also become rhetorical (e.g. private.myPrivateFunc).

Test Overload

This can be a mixture or hybrid of a few AntiPatterns. Examine the below code:

module.exports = {
    myPubFunc: async function() {
        let val = await myPrivFunc();

        // do something (perhaps, call 'myPrivFunc' again, if necessary);

        return true;
    }

	/* test-code */
	,testPrivFunc: function(fn) {
        myPrivFunc = fn;
    }
   /* end-test-code */
}

In this poor solution, a special method is provided to pass in another function and assign it to myPrivFunc, thus overwriting the original function. The testPrivFunc is only used for unit tests, however, and ignored in production. You’ll see that this test function is enclosed in comment blocks. Developers will use tools like gulp and plug-ins like gulp-strip-code to remove code between these comment blocks when building for production in order to keep production code clean. It’s nice, I guess, to want clean production code. But, why would anyone want development code dirty? Why can’t we keep both instances of code clean and make our lives easier in debugging?

Dependency Injection

This, by far, is the most complex AntiPattern. And, just to secure private methods for unit testing, it’s a complete waste of time. See the code below (non-ES6):

function PublicFuncs(privateService) { 
    this.privateService = privateService;
}

PublicFuncs.prototype.myPubFunc = async function() {
    let val = await this.privateService.myPrivFunc();

    // do something (perhaps, call 'myPrivFunc' again, if necessary);

    return true;
}

module.exports = {
    PublicFuncs: PublicFuncs
}

Notice that myPrivFunc is property of a service provider being supplied via some type of dependency injection at instantiation. Something like the above code would create a scenario like the following in your consuming code:

var publicFuncs = require('./publicFuncs').PublicFuncs(privateService);

var result = publicFuncs.myPubFunc();

While this technically could work, it’s completely unnecessary and absolute overkill. Dependency injection is fantastic for creating loosely-coupled code between services and service consumers NOT between public and private methods within the same class or module.

So, now that you’ve seen a couple of ways how NOT to unit test private functions, the next few pages will show you how to do it correctly.

Like What You See?

Subscribe to receive new posts in your inbox.

Privacy Preference Center