You have picked up Mockito and you are interested in some good practices to avoid hangovers.
Don’t mix with Spring Integration Test
Mixing spring integration test and mockito can produce strange border effects like : singleton replaced by mocks,…
and will also lose the main benefit of mockito tests : speed !
Avoid abstract testcases
When something breaks it simply takes too long to diagnose.. An alternative is to create custom assertion and factory methods that can be reused.
-> prefer composition over inheritance.
Don’t mock your model
Prefer simply using your model
Campaign campaign = new Campaign(); campaign.setAssignee(office); campaign.setType(PersonTypeCode.MEMBER); campaign.setCreationUserLocation(office); campaign.setOrganization("google"); campaign.calculateEndDate();
Over mocking it
Campaign mockCampaign = mock(Campaign.class); when(mockCampaign.getAssignee()).thenReturn(office); when(mockCampaign.getType()).thenReturn(PersonTypeCode.MEMBER); when(mockCampaign.getCreationUserLocation()).thenReturn(office); when(mockCampaign.getOrganization()).thenReturn("google"); when(mockCampaign.getCalculatedEndDate()).thenReturn(new DateMidnight());
Easier to read and you will may be add convenient contructor/factory methods to your production or test codebase… remember to put the code where it belongs.
Don’t abuse mocks
Mockito isn’t a Panacea. If all you have is a hammer, everything looks like a nail…
For example testing an xstream converter
Don’t use mock, it requires more code… and you don’t really verify the output xml format (id,type,label)
mockWriter = mock(HierarchicalStreamWriter.class); mockMarshalContext = mock(MarshallingContext.class); discriptionTargetConverter.marshal(mockTarget, mockWriter,mockMarshalContext); verify(mockWriter, times(3)).endNode(); verify(mockWriter, times(3)).startNode(anyString()); verify(mockWriter, times(3)).setValue(anyString());
It’s much more easy using xstream “as-is”
comparaisonString= "<Target> <id>3</id> <type>" + type+ "</type> <label>firstname lastname</label></Target>"; XStream xstream = new XStream(); xstream.registerConverter(discriptionTargetConverter); assertEquals(comparaisonString, StringUtils.replace(StringUtils.replace(xstream.toXML(target), "\n", ""), "\r", ""));
For more advanced xml assertion… check xmlunit
Don’t mock servlet api
org.springframework.mock.web package contains a comprehensive set of Servlet API mock objects, targeted at usage with Spring’s Web MVC framework, which are useful for testing web contexts and controllers. These mock objects are generally more convenient to use than dynamic mock objects such as mockito.
Don’t replace asserts with verify
Taken from this article
The easiest methods to understand and test are methods that perform some sort of work. You run the method and then use asserts to make sure everything worked.
In contrast, mock objects make it easy to test delegation, which is when some object other than the SUT is doing work. Delegation means the method’s purpose is to produce a side-effect, not actually perform work. Side-effect code is sometimes needed, but often more difficult to understand and debug.
If your test code contains assert methods then you have a good test. See for example the pmd rule for junit.
If it doesn’t contain asserts, and instead contains a long list of
verify() calls, then you’re relying on side effects. This is a unit-test bad smell, especially if there are several objects than need to be verified. Verifying several objects at the end of a unit test is like saying, “My test method needs to do several things: x, y, and z.” The charter and responsibility of the method is no longer clear. This is a candidate for refactoring.
Finally “if it’s hard to…”
Junit and Mockito drive a fair amount of refactoring for me.
If it’s hard to read… it’s hard to test.
If it’s hard to test… it’s hard to use.
If it’s hard to test… you’re probably doing it wrong.
If it’s hard to test… take a look at the design and test it again !