
How to Test Private Functions in JS Modules - jonahkagan
http://engineering.clever.com/2014/07/29/testing-private-functions-in-javascript-modules/
======
daniellmb
Using the NODE_ENV is nice simple solution but when you need more there is a
great dependency injection module called rewire that adds a special setter and
getter to modules so you can modify their behavior such as: inject mocks for
other modules or globals like process, leak private variables override
variables within the module.

This is especially nice because you don't need to add any special if
statements to the module code you just load your module under test using
rewire instead of require.

// file: test-stats-rewire.js

var rewire = require('rewire');

var assert = require('assert');

var stats = rewire('./stats');

// leak private method sum for testing

var sum = stats.__get__('sum');

assert.equal(sum([1]), 1);

assert.equal(sum([1, 2, 3]), 6);

------
joebadmo
If you really want to buy into the module pattern, it seems like anything
that's enough of a unit that you'd want to test could be in its own module.

In the example given, the sum function could be its own module that you
require into the stats module. That way you could test them independently, and
the stats module could simply expose its own appropriate methods.

This has the added benefit of making the sum function reusable.

Personally I prefer this approach to introducing environmental concerns into
your code.

~~~
jonahkagan
That's a great point. I definitely agree that erring on the side of modules is
better. I just worry about times when the purpose of a module is not clearly
defined at the outset (e.g. when it only contains one function that is only
used in one other module). I have often seen that devolve into the "helper"
module, where random functions collect.

I'm also not sure I buy the assertion that all code you would want to test is
code you would want to export publicly. Do you have any reasoning to support
that idea?

~~~
dragonwriter
> I'm also not sure I buy the assertion that all code you would want to test
> is code you would want to export publicly. Do you have any reasoning to
> support that idea?

All code you would want to test (or, even, to have exist) is either code that
is in publicly exported functions or code whose pathways can all be exercised
via interaction with the publicly exported interfaces, since code pathways
that are neither in publicly exported functions nor reachable through publicly
exported functions is _dead code_.

If its not testable via the public interface, it shouldn't exist.

~~~
wmayner
What if a public function is very complicated—too complicated to be considered
a unit—and it calls several simpler private functions? Those helpers should be
tested with their own unit tests, but shouldn't be exported.

It's not just about coverage in terms of code execution; you also want the
right test “resolution”, so you can quickly find the level of abstraction
where a bug is, and so you can prove correctness of the parts of a complicated
function as you build it.

~~~
CrossEye
The other side of this, though, is that you're now coupling your tests to the
implementation of your solution and not the interface you want to present. You
can't simply refactor your code to improve it; you will also have to find the
failing tests, remove them, and write new ones for your new private functions,
all while the public behavior of your system has remained working perfectly.

That's my primary reason for not testing private functions.

My alternative is simple, and has been stated elsewhere in the thread; if a
function rises to the level of complexity of really needing its own tests,
then it probably should be exposed as a public function _somewhere_ in my
system. Otherwise, I haven't factored the problem properly yet.

~~~
wilmoore
Exactly...coupling is more detrimental than one would think. As your codebase
gets larger and more developers on-board and features change, what should have
been a simple refactor can turn into a nightmare as your test suite starts to
give false negatives because you've changed the implementation or removed a
now unused private function that your tests relied upon directly. Writing unit
tests directly against private functions is a good way to ensure your team's
velocity doesn't scale as well as it should.

Unit tests will serve you better when written to assert results rather than
implementation details.

------
kevin1024
Very cool solution! I've also seen claims that the private methods of modules
should not be tested, since they don't represent the public interface of the
module and refactorings are likely to change the private methods. If the
private methods are complicated enough to warrant testing on their own,
ideally they should be extracted into their own module. Not sure if I agree
but it's something to think about!

~~~
jonahkagan
What if the private methods are complex but also module-specific? For
instance, if they deal with a data type that is private to the module?

When you pull out complex code like this into another module, how do you
specify that the new module is actually private to the old module?

------
mthenw
Don't test methods. Test behaviour that stands behind them. Unit in "unit
testing" stands for behaviour not method/function. Private methods are private
because they should not be exposed outside, never. Changing internal
implementation of module should not crash test suite.

------
backspaces
Why aren't you discussing the es6 loader which is available now?

[https://github.com/ModuleLoader/es6-module-
loader](https://github.com/ModuleLoader/es6-module-loader)

It can deal with both AMD and CommonJS modules, as well as es6 import/export.
It does not need traceur and will work with today's JS. And is built upon the
standards based System.js which basically provide loader hooks for node, JS,
and even Web Components if they so desire.

It is sure nice to get rid of the forrest of <script> tags and not be
concerned about order of dependencies.

------
qubyte
I gave a lightning presentation on this subject last month. A better solution
is to put the private methods into (sub)modules. This makes them public to the
file system and gives you the ability to tune what you make public via your
module API. Ideal for testing purposes and good for module structure in my
opinion. The slides can be found here:
[https://speakerdeck.com/qubyte/writing-testable-private-
meth...](https://speakerdeck.com/qubyte/writing-testable-private-methods-with-
node-dot-js-modules)

~~~
qubyte
P.S. see option 3 in that presentation.

------
derickbailey
exposing methods for the purpose of testing is bad design, whether or not you
are only doing it in a test environment. if you have a method that is
sufficiently complex and warrants its own testing, put it in it's own module
file and test that module file on it's own - no need to break your design and
modify your runtime module exports based on runtime environment checks

[http://lostechies.com/derickbailey/2014/01/03/semantics-
modu...](http://lostechies.com/derickbailey/2014/01/03/semantics-modules-and-
testing-why-and-how-i-test-internal-components-not-private-methods/)

