Wednesday, January 16, 2008

How to Mock an object ?

In today's article, we'll see how to build Mock objects from a normal object and what are the rules that we should follow while creating objects so that they can be mocked.

Mock objects are meant for replacing the actual domain object or an object collaborator with an 'expected' functionality. Basically here are the things we can do with a mock object.
  • We can set expectations about the object's behavior.
  • We can simulate error conditions that might occur in real life situations.
  • We can eliminate the dependency on the domain object so that we don't have
    to worry about setting up a separate environment for testing our small
    piece of code.
With that said, lets also see things we aren't supposed to do with mock object. Mock object's behavior should be restricted to its expectations. The number of objects we mock for testing a given piece of code should not be more than a small value like 2 to 3. If we have to mock too many objects to make our code work then we need to seriously consider re-factoring our code into small pieces so that we can test them using less number of mock objects.

There're again two cases you should consider while writing a mock object they are..
  • Mocking an Interface.
  • Mocking a Class

Mocking an Interface:

Creating a mock object out of a interface is very simple and straight forward. Your mock object can simply implement the interface and behave the way exactly as you expected. Lets look at an example on how to do it with a sample Interface.

Public interface Request
{

public String getParameter(String paramName);

}

Now, lets try to mock this interface

public class MockRequest implements Request
{

String _expectedValue = null;

public void setExpectedResult(String pVal)
{
this._expectedValue = pVal;
}

public String getParameter(String pName)
{
return _expectedValue;
}
}


At the first glance, you will know that my mock object has nothing to do with how the actual implementation of the Request interface gets its values from. It can get it from a simple hashmap or get it using a complex logic like going to DB, we don't care ! All we care about is what is the result that we expect from this object. This is exactly what we're doing by adding a method 'setExpectedResult()'. We just describe what we need from the mock object and nothing more.

Now in our test class we can simply write the code like this ..

public class SomeTest extends TestCase
{
public void testOneMethod()
{

MockRequest req = new MockRequest();
req.setExpectedResult("PURCHASE");

DomainObjectToTest test = new DomainObjectToTest(req);
test.callMethodTotest();

}
}

Lets assume that 'callMethodToTest()' method invokes getParameter() of the request object that is passed as a parameter to the constructor. With the mock object, we have control over what values that our code receives when it eventually calls the 'getParameter()' method on the request object.

Mocking a Class:

Mocking a class is done in pretty much the same manner as interfaces. The mock object is created by extending from the actual domain object instead of implementing an interface. The pattern to wrap a behavior around a given method remains the same as described above.

There're some rules we should follow while creating the actual domain object before we start mocking it.

  • The Domain object should be extensible. It can't be a final class.
  • The Domain object's default constructor should be visible atleast to its sub classes. So, the allowable access modifier to a default constructor is 'protected'.
  • We should not mock the very object we're trying to test in the first place.

The first two points are intuitive but I wanted to stress more on the third point here. You can check my previous article "Testing using Mock Objects using Junit", in the article I have mentioned two methods for abstracting away the singleton invocations from a given class. In one of the methods I've said that we can move the singleton invocations to a separate methods so that we can override them by returning our mock objects instead of actual singletons. This method is clearly not suggestible according to the third point I specified above. I mentioned that approach there because its easy to start off as a beginner, but the ideal way to handle that situation is always by using 'Dependency Ingestion'.

There're many other things that we can achieve and verify using the mock objects, but all those implementations are too tedious to implement manually, so we leave that to mock object generators. Mock object generators are tools to create mock objects out of real time objects, they come particularly handy while mocking interfaces. We'll discuss more about these tools in my coming articles.

Going further we'll also discuss about some famous design principles which could help us write de-coupled code while implementing a functionality. Till then, keep glued to my blog for updates !!



Powered by ScribeFire.

No comments: