Skip to content

Instantly share code, notes, and snippets.

@dfkaye
Last active December 19, 2015 14:48
Show Gist options
  • Save dfkaye/5971486 to your computer and use it in GitHub Desktop.
Save dfkaye/5971486 to your computer and use it in GitHub Desktop.
Testing private functionality in JavaScript using annotations or closure naming conventions - followup to https://gist.github.com/dfkaye/5959089

10 JUL 2013

Start with the annotated example, from http://philipwalton.com/articles/how-to-unit-test-private-functions-in-javascript/ by @philwalton

This is an alternative response. The previous TDD-with-greenfield response is here => https://gist.github.com/dfkaye/5959089

var myModule = (function() {

  function foo() {
    // private function `foo` inside closure
    return "foo"
  }

  var api = {
    bar: function() {
      // public function `bar` returned from closure
      return foo() + "bar"
    }
  }

  /* test-code */
  api._foo = foo
  /* end-test-code */

  return api
}())

In Phil's original post, the annotation comments surround the api._foo assignment, which exposes foo for testing but marks this statement for removal by the build tool that strips test-code annotations from the source AFTER tests, and BEFORE copy+deploy.

I objected to the use of these annotations around temporary code. Not a terrible offense but source modification seems an extra step I have to remember to annotate.
Lucky for us the build tool removes these.

The larger question, though, is how to access the private function another way.
Here I think the annotation approach can be used but in a different way - probably more cumbersome to get working in a build tool, but once done would be portable enough for re-use in the ecosystem.

In this case we start with the anonymous function. The first step is to name it or annotate it with something like "closure." Next, apply the build tool to scan files for these named functions, extract the function body, and write that to a closure test file directory. That will make the function's content global so there may be naming issues, but at least we won't be erasing anything from the source. Finally, execute the corresponding test/spec against this file.

The new source would be:

var myModule = (function closure() {

  function foo() {
    // private function `foo` inside closure
    return "foo"
  }

  var api = {
    bar: function() {
      // public function `bar` returned from closure
      return foo() + "bar"
    }
  }

  return api
}())

And the extracted source to test against would be:

function foo() {
  // private function `foo` inside closure
  return "foo"
}

var api = {
  bar: function() {
    // public function `bar` returned from closure
    return foo() + "bar"
  }
}

The tests can still execute against foo() and api.bar().

@dfkaye
Copy link
Author

dfkaye commented Jul 11, 2013

I've moved the second comment to a new gist here - https://gist.github.com/dfkaye/5987716

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment