09 October 2006

Between not inside

A frequent question from new users on the jMock users' mailing list is how to use jMock to mock out one method of an object while testing another method of the same object. The scenario usually involves inheritance: how can one mock out a superclass method to test the subclass. A recent query had a subtle twist: the user wanted to mock out an interface method, but that interface method was implemented by a superclass and called by a subclass, as follows:
public interface I {
    public void doSomething();
}

public abstract class A implements I {
    public void doSomething() {...}
}

public class B extends A {
    public void doLotsOfStuff(){
        ...
        doSomething();
        ...
    }
}
Mock objects are a tool for designing/testing the interactions between objects. In the code above class B is calling doSomething on itself. There is no need to use mock objects to test the B class. Tests for that exercise the functionality of doLotsOfStuff should not care that it calls doSomething somewhere down the line. That's just an implementation detail.

2 comments:

Balaji said...

For example, a class that represents an entity (an object representation of a persistent business concenpt) might extend from a base class that provides standard CRUD functionality. The entity class might have many operations that results in change of its state and hence would need to call, say a modify(), method on the super class to persist the state change.

Because unit testing is basically endo testing/white box in nature it should really be having an expectation that the method being tested did call the modify() method on the super class.

At the same time it should be possible to mock the modify() method on the super class because the test does not really want to call the underlying persistence mechanism (say a RDBMS)

-- Balaji

Steve Freeman said...

Good heavens, it's been a while since we looked at this posting...

This is quite a nice example of listening to the tests. If the business types inherit CRUD functionality, then they're mixing responsibilities. The conventional view these days is that entities should model the domain and that the persistence stuff should be separate, that's what tools like Hibernate are for.

So this test difficulty is trying to tell you that there's a clash in the design.