The oxford dictionary defines mock as – “make a replica or imitation of something”. That very much holds true in the case mock assisted unit testing.
My definition…“Mocking is the discipline of identifying the dependencies of the unit being tested and thereafter providing imitations of that dependency, such that the class being tested has no knowledge whether the dependency is real or an imitation.”.
There is a distinction on what you really expect to test in a unit test – State verification vs Behavior verification. I would point you to an excellent article by Martin Fowler regarding the same – http://martinfowler.com/articles/mocksArentStubs.html
In the real world the difference between the two blur and sometimes for a good reason. You do not have all the time in the world to sit down and write the ideal set of unit tests for each. State verification typically checks to see if the state of objects is as expected after the tests have run. Behavior verification is about checking to see if certain methods were invoked (and how many times, and what arguments were passed ,etc).
Using Mock frameworks you can stub out what data you want returned from a call to a dependent class. And that is what is of interest to me. Imagine a service class calling a classic data access class. I want to test the service class but stub out the calls to the DAO. At the same time I want the DAO to return different sets of data so as to exercise my different paths in the service class.
In the Java sphere there exists a few strong frameworks to help the
developer in mocking dependencies. In this blog I will
cover examples of three frameworks – EasyMock, JMock and Mockito.
The frameworks typically provide the following features:
- Mock both classes and interfaces (you cannot mock final methods or final classes).
- Return your own data from calls to mock objects.
- Allows you to mock an exception from the mock object.
- Chain multiple mock calls.
- Specify how many times a method must be called in a unit test.
- EasyMock and Mockito support partial mocking.
Lets look at real examples. As usual the complete Eclipse project is zipped up and available at the very bottom.
EasyMock
EasyMock follows the following design paradigm:
- Create the Mock
- Connect the mock with the object being unit tested
- Set up the expectation on the mock (which methods on the mock need to get invoked, how many times, etc). To set up the expectations you call methods on the mock and thats it. The mock object will record the facts so as to verify it later.
- Replay mode. Hereafter the mock will keep track of invocations to itself and throw exceptions if
- Execute the test
- Verify the mock invocations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
1: import static org.easymock.EasyMock.createControl; 2: import static org.easymock.EasyMock.expect; 3: import static org.easymock.EasyMock.replay; 4: import static org.easymock.EasyMock.verify; 5: private List vazips = new ArrayList(); 6: private LookupDataServiceImpl svc; 7: private LookupDao mockdao; 8: public void setUp() { 9: vazips.add("20147"); 10: vazips.add("20191"); 11: // create the object to test 12: svc = new LookupDataServiceImpl(); 13: // create the mock dao 14: mockdao = createControl().createMock(LookupDao.class); 15: svc.setLookupDao(mockdao); 16: } 17: public void test_NoExpectationsRecorded() { 18: // - no expectations are recorded 19: // - WILL FAIL the test since EasyMock requires you to 20: // - record the expectations 21: // - Switch to replay mode and run test 22: replay(mockdao); 23: // - invoke test 24: svc.getZipCodes("va"); 25: // - verify WILL NOT GET CALLED...will fail in previous step 26: verify(mockdao); 27: } |
In this test case I have not recorded any expectations. By default EasyMock mocks will then expect that no invocations can be made to it. This test case will fail with an error (entire stack trace not included)
1 2 3 |
java.lang.AssertionError: Unexpected method call getZipCodes("va"): |
Now lets look at a happy path examples where an expectation is provided.
1 2 3 4 5 6 7 8 9 10 |
1: public void test_CorrectExpectationIsRecorded() { 2: // - One expectations are recorded 3: mockdao.addZipCode("va", "11122"); 4: // - run test 5: replay(mockdao); 6: svc.addZipCode("va", "11122"); 7: // - verify 8: verify(mockdao); 9: } |
This test case will pass since we have recorded one expectation and the test execution did invoke the expected method, which was verified in the call to verify.
Now lets try to stub out the data that is returned from our DAO object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
1: public void test_VerifyReturnData() { 2: // - One expectations are recorded 3: expect(mockdao.getZipCodes("va")).andReturn(vazips); 4: // - run test 5: replay(mockdao); 6: List<String> zipcodes = svc.getZipCodes("va"); 7: for (Iterator<String> iter = zipcodes.iterator(); iter.hasNext(); ) { 8: System.out.println((String) iter.next()); 9: } 10: // - verify 11: verify(mockdao); 12: assertTrue(zipcodes.size() == 3); 13: } |
Variable vazips holds some hardcoded stub data. We would like that a call to dao.getZipCodes with an argument of statecode=VA return us this test data. The way we do this is in expectation
1 2 |
expect(mockdao.getZipCodes("va")).andReturn(vazips); |
To throw an exception from our DAO use:
1 2 |
expect(mockdao.getZipCodes("va")).andThrow(new RuntimeException("mock runtime exception")); |
As you can quickly see there is some amount of value to mocking out dependencies. What you have to guard is an over-dependence on mocking. I have seen test cases that set up so many expectations that after a while it is hard to understand what they were really testing. If you only do behavior verification then I personally think you have not unit tested the code. In the end of the day everything is about business logic and data. Your unit tests should verify those. As in the last example we have used EasyMock to return some test data so that we can unit test different execution paths in our service.
JMock
JMock is very similar in that you set up expectations, then execute and finally verify.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
1: import org.jmock.Expectations; 2: import org.jmock.Mockery; 3: import org.jmock.integration.junit4.JMock; 4: import org.jmock.lib.legacy.ClassImposteriser; 5: public void test_VerifyReturnData() { 6: final String stateCode = "va"; 7: // - record your expectations here 8: context.checking(new Expectations() { 9: { 10: oneOf(mockdao).getZipCodes(stateCode); 11: will(returnValue(vazips)); 12: } 13: }); 14: // - Execute test 15: List<String> zipcodes = svc.getZipCodes("va"); 16: for (Iterator<String> iter = zipcodes.iterator(); iter.hasNext(); ) { 17: System.out.println((String) iter.next()); 18: } 19: // - verify 20: context.assertIsSatisfied(); 21: Assert.assertTrue(zipcodes.size() == 3); 22: } |
If you had to throw exceptions from your mock then
1 2 3 4 5 6 7 |
1: context.checking(new Expectations() { 2: { 3: oneOf(mockdao).addZipCode("12121", "ca"); 4: will(throwException(new RuntimeException("mock runtime exception"))); 5: } 6: }); |
Mockito
Mockito is a relatively new framework. Where it differs from EasyMock and JMock is in the way it deals with expectations. In the case of EasyMock and JMock you have to record the expectations. Mockito does not do require you to do that. It lets you verify mock invocation verifications (of your choosing) AFTER the test is executed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
1: import static org.mockito.Mockito.mock; 2: import static org.mockito.Mockito.verify; 3: import static org.mockito.Mockito.when; 4: public void setUp() { 5: vazips.add("20147"); 6: vazips.add("20191"); 7: // create the object to test 8: svc = new LookupDataServiceImpl(); 9: // create the mock dao 10: mockdao = mock(LookupDao.class); 11: svc.setLookupDao(mockdao); 12: } 13: public void test_Mock() { 14: // NOTE: Mockito does not have concept of expectations 15: // you execute the test with the mock and after the test 16: // validate any method behaviors you want 17: // run test method 18: svc.getZipCodes("VA"); 19: // verify 20: verify(mockdao).getZipCodes("VA"); 21: } |
In this case you connect your class to the mock object as before, then simply run your test. After the test is executed you verify that expected methods were called. In this case a call to getZipCodes with an argument of “VA”. Change the argument to “CA” and the verification will fail.
Here is how you would stub data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
1: public void test_VerifyReturnData() { 2: // stubs the return values on the mock dao 3: when(mockdao.getZipCodes("va")).thenReturn(vazips); 4: // run test method 5: List<String> zipcodes = svc.getZipCodes("va"); 6: System.out.println(zipcodes.size()); 7: for (Iterator<String> iter = zipcodes.iterator(); iter.hasNext(); ) { 8: System.out.println((String) iter.next()); 9: } 10: // verify 11: verify(mockdao).getZipCodes("va"); 12: assertTrue(zipcodes.size() > 0); 13: } |
Finally if you were to mock exceptions..
1 2 |
when(mockdao.getZipCodes("ca")).thenThrow(new RuntimeException("mock runtime exception")); |
Each has its own advantages but none so ground breaking that one rules over the other. Use what you are comfortable with.
Click here to download the zip containing the source code and eclipse project. Please download libraries from: http://www.easymock.org , http://www.jmock.org , http://www.mockito.org