HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Method for gaining access to private members in JavaScript for testing purposes

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
methodjavascriptpurposesprivatetestingformembersaccessgaining

Problem

When running unit tests in JavaScript it is often useful to gain access to private members. Previously I would add an extra snippet of code inside the class definition (or whatever one calls this in a prototype-based language) to open up the object. Something like this was usually sufficient:

this.internal = function(name) {
    return eval(name);
}


(And before anyone comments of the evils of eval, keep in mind that I'm using only this for testing purposes and it is not included in the final deployment file - I use a grunt script and some regexp to automatically remove it).

This (above) has been working just fine, but I had a niggling feeling that a better (and more general) solution should be possible. I was doing some other work on code instrumentation in the browser and realized that this was a good candidate for some real-time code instrumentation. So, I created this simple functionality for adding some extra functions to a class that allows access to first-level private members:

```
var CodeInspector = new function() {
var prefixPattern = /^[a-zA-Z_$][0-9a-zA-Z_$]*/;

this.instrumentClass = function(classObject, prefix) {
if(Object.prototype.toString.call(classObject) !== "[object Function]") {
return false;
}
if(prefix === undefined || prefix === null) {
prefix = "";
}
else if(!prefixPattern.test(prefix)) {
return false;
}

var internalCode = " \n\
this."+prefix+"getPrivate = function(name) { \n\
return eval(name); \n\
} \n\
this."+prefix+"setPrivate = function(name, value) { \n\
eval(name+' = value'); \n\
} \n\
this."+prefix+"callPrivate = function(name) { \n\

Solution

gain access to private members

Unit tests, as far as I know, is a form of black box testing. The test doesn't concern about the internals of the implementation, only the input and output of the operation. Thus your tests should not be concerned about internal state.

If you really are concerned about internals, either:

-
Make the properties public instead. Specifically, you can use the convention of prefixing _ to the member name to tell users "Ok, I'm public but you should treat me as private."

-
Use accessors (getters and setters). This way, your code isn't full of "debugging" code, but officially usable (albeit unnecessary) code.

-
Another way is to use tools like JSDev. These tools allow you to write debug code and strip them off during production (through a build step). If you don't mind checking-in debug code to your VCS, consider this approach.

You're adding too much complexity in your code to do encapsulation. Given time and effort, nothing in JS is actually private. Native functions can be monkeypatched to hack into enclosed code, dev tools can peer into closures. It's easier to do pseudo-private using the _ private convention.

Context

StackExchange Code Review Q#85165, answer score: 4

Revisions (0)

No revisions yet.