Subclass Mock Objects
Jakob Jenkov |
Subclass mock objects is a mock object that is created by subclassing the class you want to test, and overriding some of its methods. Let's look at a simple class:
public class MyUnit {
protected MyDependency dependency = null;
public MyUnit(MyDependency dep) {
this.dependency = dep;
}
public void doTheThing(String param) {
if("one".equals(param)) {
dependency.callOne();
} else {
dependency.callTwo();
}
}
}
The class MyUnit is the class I am trying to unit test. In this unit test, I want to check if
the MyUnit class calls the MyDependency class correctly. There are 3 ways to do this:
- Create a Mock implementation of the
MyDependencyclass, using a proxy object - Create a subclass mock of the
MyDependencyclass, and override thecallOne()andcallTwo()methods - Create a subclass of the
MyUnitclass itself, and use that during testing.
In this text I will show you how to do nr. 3. From that method it should be fairly easy to figure out how to do number 2, in case you want that.
Using method nr. 3 requires the following steps:
- Encapsulate calls to
MyDependencyinsideMyUnit - Create a subclass of
MyUnit - Override the
MyDependencycall encapsualation methods.
I will show you how to perform these three steps, throughout the rest of this text.
Step 1: Encapsulate calls to MyDepedency
The first thing to do is to refactory the MyUnit class, so that all calls to the
MyDependency class are encapsulated in their own methods. Here is how that looks:
public class MyUnit {
protected MyDependency dependency = null;
public MyUnit(MyDependency dep) {
this.dependency = dep;
}
public void doTheThing(String param) {
if("one".equals(param)) {
callOne();
} else {
callTwo();
}
}
protected void callOne() {
dependency.callOne();
}
protected void callTwo() {
dependency.callTwo();
}
}
Notice how the two calls to MyDependency.callOne() and MyDependency.callTwo() are
now encapsulated in two protected methods, callOne() and callTwo().
We are now ready to create the MyUnit subclass.
Step 2: Create a Subclass Mock of MyUnit
The second step is to create a subclass mock of the MyUnit class. Here it is:
public MyUnitMock extends MyUnit {
protected boolean callOneCalled = false;
protected boolean callTwoCalled = false;
@Override
protected void callOne() {
this.callOneCalled = true;
super.callOne();
}
@Override
protected void callTwo() {
this.callTwoCalled = true;
super.callTwo();
}
}
Notice how the two overridden methods records if they are called or not, by setting a boolean to true.
The next step is to use the MyUnitMock in your unit test.
Step 3: Using the MyUnitMock Class in Your Unit Tests
Here is a unit test method that uses the MyUnitMock class:
@Test
public void test() {
MyUnitMock myUnitMock = new MyUnitMock();
myUnitMock.doTheThing("one");
assertTrue (myUnitMock.callOneCalled);
assertFalse(myUnitMock.callTwoCalled);
//reset mock before next call
myUnitMock.callOneCalled = false;
myUnitMock.doTheThing("two");
assertFalse(myUnitMock.callOneCalled);
assertTrue (myUnitMock.callTwoCalled);
}
First an instance of the MyUnitMock class is created. Second, the doTheThing()
method is called. Third, assertions are made about whether the callOne() and callTwo()
method were invoked.
Summary
As you can see, it is possible to test almost all of a class by using subclass mocks, as described above. There are, however, situations where it works better to use a completely separate mock dependency object with the original class instead. Exactly when, depends on the concrete application.
Just keep in mind, that the above is just a suggestion - one possible method. Use it when it make sense, and don't use it when it doesn't make sense. Use your judgement!
| Tweet | |
Jakob Jenkov | |











