Monday, April 2, 2007

Mock The Planet

I'm writing a simple service that does a database query and returns result to caller via web services. Before I declare the completion of this project, I want to write unit tests. The unit tests should cover all my business logics, which mainly made of data transformations. The unit tests cannot really connect to the database since they will be ran on the build server every night. So I'll "mock the planet".
The notation of "mocking" is to fake some behaviors in order to test some part of codes. In my case, I want to fake the database connection and to test my data transformation codes.
There are many ways to mock behaviors, all which require the usage of interfaces and implementations. The basic idea is that the class you want to "mock" implements an interface. For the purpose of testing, one needs to write "mocked" implementation of the interface and use the "mocked" object.
A common way of "mocking" is to use Spring IoC. A different spring application context is used during unit tests. For example, my data transformation service uses an interface called "PersonDAO". In the real application, I use Spring IoC to inject "PersonDAOMySQLImpl" to the data transformation service. However, in unit test, I inject "MockedPersonDAOImpl". Both "PersonDAOMySQLImpl" and "MockedPersonDAOImpl" impement "PersonDAO", and both declare a method "Person getPerson(String name);". The actual implementation of this method connects to the database and returns a Person object for a given name. The "mocked" implementation always returns the same dummy Person object. During unit tests, I can then try to transfer the dummy Person object and assert my transformation code.
A big shortcoming of this method is that you can only get one dummy object back from the "mocked" class. You can try to trick the "mocked" object by passing parameters to it and return different dummy object for different inputs. The fact is that you can only get one "mocked" implementation for an interface using Spring IoC will always make mocking multiple behaviors difficult.
EasyMock solves this problem. In EasyMock, you mock the behavior of an interface inside the unit tests. In my case, I can create a reference to "PersonDAO" interface and use EasyMock to get the interface. I then tell EasyMock what I want "mocked" person to return when I pass in a parameter. I can easily mock different behaviors over and over again. EasyMock doesn't just mock behavior, it only checks for method executions. You can tell EasyMock that a specific method in the interface should be executed N times. If during unit tests, the method doesn't get executed N times, the unit tests would fail.
EasyMock is great tool to mock dependency services.

No comments: