tags:

views:

34

answers:

2

Hi -I read about 2 JavaScript testable patterns, but I am not sure how they differ and which one should I use.

Pattern 1:

function class () {
    this.propertyA = null;
    this.methodA = function() {
        alert('');
    }
}

var object = new class();
object.methodA();

Pattern 2:

var object = (function() {
    var propertyA = null;
    return {
        methodA: function() {
            alert('');
        }
    }
}());
var object = new class();
object.methodA();

What are the differences? Which one should I use for unit testing with jQuery's QUnit? Please note that jQuery plugins are not an option for my requirements (not UI testing, business logic only). Thank you.

+1  A: 

The difference between these patterns is that the second pattern "hides" the internal properties -- once you have your object, you can't get to propertyA, you can only call methodA (which will itself have access to propertyA). So pattern 2 is better from an object-oriented encapsulation standpoint.

In terms of testing it shouldn't really matter, because you should be testing based on your "public" API -- the methods you call in your test should be the methods a user of your object would call -- and the two patterns should be identical. But I can imagine a scenario where, just for a test, you might need to set propertyA from the "outside". That would probably indicate a design problem. But if you can't redesign to prevent such a scenario, then you would need to use pattern 1.

JacobM
Thank you that was really useful.
Bruno Ligutti
+1  A: 

QUnit doesn't really care one way or the other. It's basically a wrapper that provides pretty output for assertions.

As for the difference between the two patterns, Pattern 1 (as you have implemented it) has all-public properties. You can do private properties, though:

function class () {
    var propertyA = null;
    this.methodA = function() {
        alert('');
    }
}

var object = new class();
object.methodA();

Pattern 2 won't actually work. You're just providing a result object wrapped in a closure, so you can't really call new on it. You would need to do it like this:

var class = (function() {
    var propertyA = null;
    return function () {
        return {
            methodA: function() {
                alert('');
            }
        };
    }
}());
var object = new class();
object.methodA();

The whole point of the new keyword is that it calls the object's constructor with a new variable bound to this. If you don't have a constructor, you're just creating a singleton.

For practical purposes, here's what's happening:

  • In Pattern 1, a new propertyA is created for each instance of class.
  • In Pattern 2 (as you implemented it), you're creating a singleton object.
  • In Pattern 2 (as I implemented it), a single propertyA is shared among all instances (like static members in C++).

This is because in Pattern 1 you're creating a straightforward constructor function, which creates a new closure around the public methods for each invocation of new. Whereas in Pattern 2, you're creating a single closure around the constructor and declaring variables outside of the constructor's scope.

C-Mo
Thank you that was really useful.
Bruno Ligutti