views:

53

answers:

2

I have a class A which contains an instance of class B, and function foo of A calls function set of B, which updates the state of B. Here is a code example (in Javascript):

A = function () {
    this.init = function (b) {
        this.b = b
    }

    this.foo = function (val) {
        this.b.set(val)
    }

    this.bar = function () {
        return this.b.get()
    }

}

B = function () {
    this.set = function (val) {
        this.v = val
    }

    this.get = function () {
        return this.v
    }
}

How do I unit-test the foo function, while keeping the test for A non-dependent on the implementation of B (using mocks and stubs and what not)?

+3  A: 

Using mocks, you can simply hand A a mock of B, which will check that set was called with the appropriate value. If you don't have a mock framework, in JavaScript you can simply create an object:

b = {  
       setCalled: false,
       expectedValue: <expected>
       set: function(val) {
         <check that val == this.expectedValue>
          this.setCalled = true;
       }
     }

in the test you setup b, create an A with the given b then call A.foo and check that b.setCalled changed to true. You can similarly add a get method to b to check A.bar.

In this case you also should check the smell Feature Envy -- when two classes are this tightly coupled you should check to make certain you are not using something incorrectly. It may be fine in your real example, but it is worth a check.

Kathy Van Stone
"small Feature Envy" should be "smell"
Bryan Ash
Doesn't this mean that the test is depending on the implementation, which is bad for TDD? What if the implementation of `foo` changes so it doesn't use `B`'s `set`?
Chetan
The request was to test with a mock B. I would not normally mock B unless the external behavior of A was how it affected B (say if B was an external library). The note about the smell is that this type of behavior (of A) can be problematic
Kathy Van Stone
A: 

I figured out the best way to do this, while making sure that A's test doesn't depend on its implementation, would be to create a mock B that has a working get and set, but writes to a temporary variable.

Code example to test A:

// Mock B
b = new function () {
    this.set = function (val) {
        this.v = val
    }

    this.get = function () {
        return this.v
    }
}

// Create an instance of A with Mock B
a = new A().init(b)

// Test A

// ...
Chetan