Unit testing private functions with mocha and node.js

I am using mocha for unit test application written for node.js

I wonder if it is possible to use unit test functions that have not been exported to the module.

Example:

I have many functions defined as in foobar.js

 function private_foobar1(){ ... } function private_foobar2(){ ... } 

and several functions are exported as public:

 exports.public_foobar3 = function(){ ... } 

The test case is structured as follows:

 describe("private_foobar1", function() { it("should do stuff", function(done) { var stuff = foobar.private_foobar1(filter); should(stuff).be.ok; should(stuff)..... 

Obviously this does not work, since private_foobar1 not exported.

What is the right way to individually test private methods? Does Mocha have built-in methods for this?

+123
javascript private unit-testing mocha
Feb 28 '14 at 14:17
source share
9 answers

If the function is not exported by the module, it cannot be called by test code outside the module. This is because of how JavaScript works, and Mocha alone cannot get around this.

In those few cases when I decided that checking a private function is the right thing, I performed some environment variable that my module checks to see if it will run in a test setup or not. If it starts in a test setup, it exports additional functions that I can call during testing.

The word "environment" is freely used here. This could mean checking process.env or something else that might be communicating with the module you are currently testing. The instances where I had to do this were in the RequireJS environment, and I used module.config for this purpose.

+58
Feb 28 '14 at 15:47
source share

Open the rewire module. This allows you (and to manipulate) private variables and functions inside the module.

So, in your case, usage would look something like this:

 var rewire = require('rewire'), foobar = rewire('./foobar'); // Bring your module in with rewire describe("private_foobar1", function() { // Use the special '__get__' accessor to get your private function. var private_foobar1 = foobar.__get__('private_foobar1'); it("should do stuff", function(done) { var stuff = private_foobar1(filter); should(stuff).be.ok; should(stuff)..... 
+181
Jul 16
source share

Here's a really good workflow for testing your personal methods, which explains Philip Walton, a Google engineer on his blog.

Principle

  • Write your code normally
  • Associate your private methods with an object in a separate block of code, mark it, for example, _
  • Surround this block of code with start and end comments

Then use the build task or your own build system (for example, grunt-strip-code) to remove this block for production assemblies.

Your test builds have access to your private API, but your production builds do not.

excerpt

Write your code like this:

 var myModule = (function() { function foo() { // private function 'foo' inside closure return "foo" } var api = { bar: function() { // public function 'bar' returned from closure return "bar" } } /* test-code */ api._foo = foo /* end-test-code */ return api }()) 

And your gross tasks like this

 grunt.registerTask("test", [ "concat", "jshint", "jasmine" ]) grunt.registerTask("deploy", [ "concat", "strip-code", "jshint", "uglify" ]) 

Deeper

In a later article, this explains the "why" of "private method testing"

+22
Jul 03 '15 at 8:13
source share

If you prefer everything to be simple, just export the private elements as well, but clearly separate them from the public API with some conventions, for example, add the _ prefix to them or embed them in one private object.

 var privateWorker = function() { return 1 } var doSomething = function() { return privateWorker() } module.exports = { doSomething: doSomething, _privateWorker: privateWorker } 
+20
Nov 27 '14 at 16:57
source share

To do this, I created the npm package, which may be useful: require-from

You basically expose private methods:

 module.testExports = { private_foobar1: private_foobar1, private_foobar2: private_foobar2, ... } 

note: testExports can be any valid name except for exports course.

And from another module:

 var requireFrom = require('require-from'); var private_foobar1 = requireFrom('testExports', './path-to-module').private_foobar1; 
+5
May 13 '14 at 14:04
source share

I added an extra function that I called Internal () and returns all private functions from there. This Internal () function is then exported. Example:

 function Internal () { return { Private_Function1, Private_Function2, Private_Function2} } // Exports -------------------------- module.exports = { PublicFunction1, PublicFunction2, Internal } 

You can call internal functions as follows:

 let test = require('.....') test.Internal().Private_Function1() 

I like this solution more because:

  • only one Internal () function is always exported. This Internal () function is always used to test private functions.
  • It is easy to implement.
  • Low impact on production code (only one additional function)
+4
Feb 23 '19 at 6:33
source share

I followed @barwin's answer and checked how unit tests can be performed using the rewire module. I can confirm that this solution just works.

The module should be necessary in two parts - public and private. For public functions, you can do this in a standard way:

 const { public_foobar3 } = require('./foobar'); 

For private use:

 const privateFoobar = require('rewire')('./foobar'); const private_foobar1 = privateFoobar .__get__('private_foobar1'); const private_foobar2 = privateFoobar .__get__('private_foobar2'); 

To learn more about the subject, I created a working example with full module testing, testing includes a private and public domain.

For more information, I recommend that you check out the article ( https://medium.com/@macsikora/how-to-test-private-functions-of-es6-module-fb8c1345b25f ), fully describing the topic, it includes code samples.

+1
Oct 24 '17 at 9:11
source share

I know that this is not necessarily the answer you are looking for, but I found that most of the time, if a private function deserves testing, it is in its own file.

For example, instead of using private methods in the same file as public ones like this ...

SIC / thing / PublicInterface.js

 function helper1 (x) { return 2 * x; } function helper2 (x) { return 3 * x; } export function publicMethod1(x) { return helper1(x); } export function publicMethod2(x) { return helper1(x) + helper2(x); } 

... you divided it like this:

SIC / thing / PublicInterface.js

 import {helper1} from './internal/helper1.js'; import {helper2} from './internal/helper2.js'; export function publicMethod1(x) { return helper1(x); } export function publicMethod2(x) { return helper1(x) + helper2(x); } 

SIC / item / internal /helper1.js

 export function helper1 (x) { return 2 * x; } 

SIC / thing / internal /helper2.js

 export function helper2 (x) { return 3 * x; } 

Thus, you can easily test helper1 and helper2 as it is, without using Rewire and other “magic” (which, as I discovered, has its pain points when debugging or when trying to switch to TypeScript, and not to mention the worst understandability for new colleagues). And the fact that they are in a subfolder with an internal name or something like that will help to avoid their accidental use in unintended places.




PS: Another common problem with "private" methods is that if you want to test publicMethod1 and publicMethod2 and make fun of helpers, then you usually need something like Rewire for this. However, if they are in separate files, you can use Proxyquire for this, which, unlike Rewire, does not require any changes in the build process, is easy to read and debug, and works well even with TypeScript.

0
Jul 17 '19 at 7:32
source share

To make private methods available for testing, I do this:

 const _myPrivateMethod: () => {}; const methods = { myPublicMethod1: () => {}, myPublicMethod2: () => {}, } if (process.env.NODE_ENV === 'test') { methods._myPrivateMethod = _myPrivateMethod; } module.exports = methods; 
0
Jul 26 '19 at 2:23
source share



All Articles