How to Unit Test Private Functions in The Revealing Module Pattern

The Problem

Several patterns for structuring JavaScript code have been around over the past few years, chief of which are probably the module and the revealing module patterns. They both manage to cope with spaghetti code that seems to be a severe problem in large enterprise web applications. The advantages of these structuring patterns are priceless; and I’m not going to go through all of them. There are lots of nice articles describing these patterns and I would recommend you to read some if you’re not already aware of them. I would like, though, to point out one significant advantage; and that is the notion of encapsulation that we borrow from the object oriented programming.

In this article I will use the AMD pattern using requireJS. In Essence, AMD is an extension of the module and revealing module patterns, so it will suit the needs of our example.

define(function(){  
    // inner methods
    var
       draw = function(from, to) { },
       redraw = function(from, to) { },
       addChartContainer = function(argument) {  },
       zoomHandler = function(startDay, daysToShow) {
           ...
           redraw.call();
       },
      .
      .
      .;

    // ctor
    var GanttChart = function(){

    };

    GanttChart.prototype = (function(){
        var publicApi = {
            constructor: GanttChart,
            draw: draw
        };

        return publicApi;
    }());

    return GanttChart;
});

The above is an example of a module for drawing Gantt charts. We can see that there are four (in fact, there are more than that) inner methods that are enclosed within a closure. We expose only the draw method to the outer world; hence, the rest methods are not accessible from outside the boundaries of the module.

That’s exactly what we are aiming for; we managed to apply real encapsulation without using any naming conventions e.g. prefixing the private members with underscore.

Regardless of the benefits that encapsulation brings to our design, we can soon come to witness an evident disadvantage; since the private members are not accessible from outside the module, we are not able to unit test them.

At this point I would like to note that there is an argument over whether we should be testing private methods or not. I’m not going to go deep into describing the pros and cons of that. I assume that you are of the opinion that every function that has got some logic in it should be unit tested.

There are several suggestions about how we can deal with the aforementioned problem. A popular suggestion is to expose the public members, as well as, the private. It’s obvious, though that we lose all the benefits of real encapsulation. We still can rely on naming conventions to indicate which members are private, but I’ not a big fan of that approach, whatsoever.

My Solution

Given the nature of JavaScript scoping, we know that there is no way that we can access the inner methods of a module. I thought that a nice idea would be to make the private methods accessible only under specific circumstances; for example, when running unit tests.

The way I managed to that was by using the publish/subscribe pattern. In practice, we would like to somehow inform our module that we are in the unit test mode. This will let the modules expose the private members that we are going to unit test.

So let’s show how I went about doing that. The updated module looks like this:

define(['pubsub'], function(pubsub){    
   // inner methods
   var
       draw = function(from, to) { },
       redraw = function(from, to) { },
       addChartContainer = function(argument) {  },
       zoomHandler = function(startDay, daysToShow) {
           ...
           redraw.call();
       },
       .
       .
       .;

    // ctor
    var GanttChart = function(){

    };

    GanttChart.prototype = (function(){
        var publicApi = {
            constructor: GanttChart,
            draw: draw
        };

        pubsub.on({
            topic: 'testMode:on',
            callback: function(){
                $.extend(GanttChart.prototype, {
                    redraw: redraw,
                    addChartContainer: addChartContainer,
                    zoomHandler: zoomHandler
                });
            }
        });

        return publicApi;
    }());

    return GanttChart;
});

First of all, we added one dependency to our AMD module and that’s the pubsub module. As the name suggests, that’s a module that implements the pub/sub pattern.

In addition, we added the following code snippet:

pubsub.on({
    topic: 'testMode:on',
    callback: function(){
         $.extend(GanttChart.prototype, {
             redraw: redraw,
             addChartContainer: addChartContainer,
             zoomHandler: zoomHandler
         });
    }
});

So basically, what we’re doing here is, we subscribe to a custom topic (testMode:on). When that event is triggered, the callback function is invoked, which extends the GanttChart’s prototype object with the private methods that we want to unit test. So, in essence, we managed to add additional methods to the prototype under the condition that the test mode is on. Those methods, will not be accessible during the development time nor in production; Unless, we deliberately trigger the testMode:on event.

Now that we have access to the private members we are free to write our unit tests; I will use jasmine in my example.

define(['ganttChart', 'pubsub'], function (GanttChart, pubsub) {
  describe('The chart module', function () {
    // inform the modules that we are in the test mode
    pubsub.trigger({
        topic: 'testMode:on'
    });

    var ganttChart;

     beforeEach(function () {
        ganttChart = new GanttChart();
     });

     afterEach(function () {
         ganttChart = null;
     });

     describe('The addChartContainer method', function () {
            it('Should add an svg element into element with the specified id', function() {
                // Arrange
                ...

                // Act
                ganttChart.addChartContainer('#someId');

                // Assert
                ...
            });
        });
   });
});

First of all, we need to inform the module that we are in test mode; so they can expose they private methods. We do that by simply publishing the ‘testMode:on’ topic. So whoever is subscribed to it, will be notified.

Once we’ve done that, we are good to go and access the private methods. You can see that we managed to access the addChartContainer even though it is not part of the public api.
Conclusion

To summarize, due to the nature of the module and revealing module pattern, we are limited to what members we can have access to. This, however, is an important issue when we want to unit tests the private methods of a module.
To avoid exposing all the members and losing all the benefits of encapsulation, we decided to follow a slightly different path. We managed to make our modules decide which members they should expose and under which circumstances. So in essence, we turned the revealing pattern into something which I like to call conditional revealing module pattern.

Comments 0

Leave a Reply