What are mock objects
From Coder's Log
Mock objects truly portray what object oriented programming is all about. They allow you to override default functional implementation with a tracer or dummy like object, which can either do nothing at all or track what methods have been invoked through out the application. The end goal of mock objects is to create unit tests that target a particular section of code. There have been a couple of tools developed to make mocking a breeze in java. EasyMock and JMock are just a couple of examples.
In order to understand how mocking works you will need to go through the process of manually creating mock objects.
Lets consider a function which generates a hash based on the current time
public class HashGenerator {
public long generateHash() {
return System.currentTimeInMillis() * 5 % 99;
}
}
In the current state, there is no way to properly test this function since its impossible to create an input and output pairs. This is where we can use a bit of refactoring to allow us to use a mock object to isolate the behavior we wish to test.
Lets create an interface and an implementation to replace the System.currentTimeInMillis(), and use it in the HashGenerator class
public interface TimeRetirever {
public long getTime();
}
public class SystemTimeRetriever implements TimeRetriever {
public long getTime() {
return System.currentTimeInMillis();
}
}
public class HashGenerator {
private TimeRetriever timeRetriever;
public HashGenerator(TimeRetriever timeRetriever) {
this.timeRetriever=timeRetriever;
}
public long generateHash() {
return timeRetriever.getTime() * 5 % 99 ;
}
}
We have effectively disconnected the HashGenerator from the System.currentTimeInMillis(), and not only are we now able to properly test this code, but we have also made it a cleaner and a reusable implementation. A good rule of thumb can be derived from this example. If a code is difficult to test its likely to be difficult to reuse and adopt to different situations. Code that is easy to test tends to be cleaner in design and easier to understand and reuse down the line.
Now that we have our real implementation lets create our mock implementation
public class TimeRetrieverMock implements TimeRetriever {
private long time;
public TimeRetrieverMock(long time) {
this.time=time;
}
public long getTime() {
return time;
}
}
This is a pretty basic implementation that will always return the same number. Lets see how we can use this in a test case now
public void testHashGenerator() {
HashGenerator generator=new HashGenerator(new TimeRetrieverMock(100))
assertEquals(5, generator.generateHash());
generator=new HashGenerator(new TimeRetrieverMock(23))
assertEquals(16, generator.generateHash());
}
We used the mock object to inject static and predictable behavior into our implementation in order to properly measure its effectiveness. Once the proper code was isolated, we were able to use standard junit assertions in order to validate results.
