Mock a mockito

Introduction
Most programmers know about the concept of unit tests and have dabbled with the Junit framework while they learn the beauty of automatic tests. However, few are those who have met Mockito, which is in fact one of the best frameworks for unit testing.
We may use a layered structure on a server to split the elements according to their functionalities, and following that train of thought we can modularize the code in logical layers. That’s where Mockito comes through.
graph LR; A[Service layer]; B[Business layer]; C[Data access layer]; D((Database)); A-->B; B-->C; C-->D;
By using a “mockers system” we can substitute a whole dependant component class with a behavioural emulation, following the behaviour driven development paradigm. The best way to explain this task is using an example, so let’s suppose we have an interface called IDocumentAccessDao
, which will be implemented by the class DocumentAccessDao
. This data access object has some database accesses using Jdbc, and while we intend to create tests to cover all of its set of instructions, it makes no sense to actually connect to the database as it may be not available and make our tests fail (and that would also be an Integration test, not a Unit test).
Process: How do we drink this?
1. Setting up the Maven dependencies
The first step is getting the testing dependencies into our project, and that’s something we can do via Maven by adding them to the pom.xml file.
❕These were the stable versions when the post was originally written
1 | <dependency> |
2. Mocking the Data Access class
❗️If we are using a component which may be also used in other classes (e.g. JDBC or JPA implementations to handle the connections to databases), it would be good to apply inheritance to those components, as they are highly reusable.
1 |
|
Let’s start by creating the test class, which we will call DocumentAccessDaoTest, but don’t forget that if you are using Spring, you may want to load the mocks from the context.xml file.
1 | <! — DATAACCESS-DAO -> |
Now let’s check the class we are going to test:
1 |
|
We can see that it uses calls to DocumentDAO
and JdbcTemplate
methods, so we would need to mock those calls to avoid running code from other classes. Therefore, we will use the following 3 attributes in our DocumentAccessDAOTest class:
documentDAO
: the entity we will test.mocker
: the database connection mocker.documentDAOMock
: we intend to execute only the code inDocumentAccessDAO
, so we will simulate it by getting default dummy values for every method invoked from this object.
The code on the initMock will follow this structure:
- Initialize the mocks: we need to know the results expected on the different calls to mocked objects. The syntax for this methods looks like
initMockForMethod (inputParameters, resultExpected)
, and will be detailed later. - Call the method we want to test.
- Check that the result obtained is the one we expected by using assert instructions. If we expect and exception, we should use an “expected” annotation.
1 |
|
As you can see, we use the class MockedDocumentValues.java
to generate the dummy values for some parameters. This class belongs to a set of common classes named Mocked*Values
on the Junit auxiliary project, to avoid duplicated values among the test cases.
Cookbook for more complex cases
I’ll do a quick syntax enumeration for all the odd situations I found:
1. How to mock a standard method
The simplest version of the syntax would be:
Mockito.when(method).thenReturn(valueExpected)
1 | Mockito.when(documentDAOMock.getLastDocumentVersion(sql)).thenReturn(1); |
2. Throwing an exception
If the method returns a value the syntax would be:
Mockito.when(method).thenThrow(new Exception())
1 | Mockito.when(this.template.update(sql, status, docId)) |
However, if the method returns void, the syntax is different, so be careful with the parenthesis on the latest part of the sentence:
Mockito.dothrow(Exception.class).when(instance).method(parameter)
1 | Mockito.doThrow(IOException.class).when(this.em). |
3. Using matchers
- When we want to return a value independently of the parameters content, we can use
Matchers.any(Object.class)
(whereObject
may be any custom class we prefer, or if use one of the classical Java types we may use their own methods:anyString()
,anyInt()
,anyList()
…).1
2Mockito.when(documentDAOMock.getLastDocumentVersion(
Matchers.anyString())).thenReturn(1); - If we want to do something similar, mixing parameters whose content we don’t mind while other values may be important, we should combine
Matchers.any(Object.class)
andMatchers.eq(instance)
1
2
3
4Mockito.when(this.template.update(
Matchers.eq(SqlDocumentManager.INSERT_DOC_AUTH_ACTION),
Matchers.any(PreparedStatementSetter.class))).thenThrow(
new RecoverableDataAccessException(MockedValues.GENERIC_DAO_EXCEPTION_TEXT)); - Another useful method is Matchers.isA(class). When we have a series of em.persist(object) and we have to find which one of them we actually need, we can determine it by pointing out the class of instance it belongs to.
1
2
3
4
5public <T> void initMockForFindFails(Class<T> entityClass, Object primaryKey) {
Mockito.when(this.em.find(
Macthers.isA(InvalidPersistanceClass.class),
Matchers.eq(primaryKey))).thenThrow(new NoResultException());
}
4. Mocking a procedure with possible input/output parameters (persist method)
Sometimes, we have to check the new primary key of an Object after it has been inserted on a database via entityManager.persist
(instanceObject). When this happens, we have to mock the method to simulate the answer received, as we do in this example.
1 | /** |
Another complex example using the doAnswer
method would be defining via answer “on the fly” not only changes on the output or return statment, but we may be able to define input/output parameters.
1 | public void initMockForMyProcedure(MyInputOutputObject object1){ |
5. Mocking a JPA query-response method as a single method
This avoids problems when several pairs of “named queries”/“getResults” are used in a single method, so the results of each one of them don’t get mixed.
1 | public <T> void initMockForCreateNamedQueryGetSingleResult(String sqlQuery, |
6. Mocking an abstract class
Abstract classes can be instanced as normal ones by mocking them with CALL_REAL_METHODS
.
1 | public void initMockers() { |
7. Mocking a ‘?’ parameter
These should be mocked with the doReturn instruction, in a similar way as throwing exceptions on methods which don’t have return statements.
1 | public void initMockForGetMap(Map<String, ?> expectedValue) { |
8. Mocking an ‘Object…’ parameter
These are called vargars parameters. E.g. To mock something like JdbcTemplate.queryForList(String sql, Object… args)
, we need to use Matchers<CLASSNAME>.anyVararg()
1 | public void initMockForQueryForList(List<String> expectedvalue){ |
Mockito limitations
- Mockito can’t mock final classes
- Mockito can’t mock static methods
- Mockito can’t mock final methods
In case you need to mock legacy code containing any of this issues, you should use Powermock, but taking into account that not all the releases of Mockito are totally compatible with Powermock.
❗️ When there is an evil static class in your application and you can’t get rid of it without messing up half your application, you may consider using a singleton pattern to avoid this issue.
1 | public final class SendMailHelper{ |
Then, in the classes we used to call SendMailHelper.method()
we add an attribute declaration, and when it is needed, we can set it for the tests (in the initMock()
method).
1 | SendMailHelper sendMailHelper = SendMailHelper.getInstance(); |
Advice about the best Junit practices
1. Test only one code unit at a time
When we try to test a unit, it may have multiple use cases. We should always test each use case in separate test case. For example, if we are writing test case for a function which is supposed to take two parameters and should return a value after doing some processing, the different use cases might be:
- First parameter can be null. It should throw an InvalidParameterException.
- Second parameter can be null. It should throw an InvalidParameterException.
- Both can be null. It should throw an InvalidParameterException.
- Finally, test the valid output of function. It should return valid predetermined output.
This helps when you do some code changes or some refactoring: running the test cases should be enough to check that functionality is not broken. Also, if you change any behaviour you would need to change some test cases.
2. Make each test independent to all the others
Don’t create a chain of unit test cases. It will prevent you to identify the root cause of the test case failures, and you will have to spend time debugging the code. Also, it creates dependency, which means that if you have to change one test case then you need to make changes in multiple test cases unnecessarily.
3. Mock out all external services
Otherwise, the behaviour of those external services overlaps multiple tests, and different unit tests can influence each other’s results.
We have to be sure each test resets the relevant statics to a known state before they run. We have to try avoiding dependences between tests and systems so running them in a different order won’t affect the outcome.
4. Name your unit tests clearly and consistently
This is the most important point to keep in mind. We must name our test cases regarding what they actually do and test. A test case naming convention which uses class names and method names for test cases name is never a good idea, as every time you change the method name or class name, you will end up updating a lot of test cases as well.
But, if our test cases names are logical i.e. based on operations then you will need almost no modification, because the application logic will most possibly remain same.
E.g. Test case names should be like (supposing EmployeeTest is our Junit class):
1 | EmployeeTest.createWhithNullIdShouldThrowException(); |
5. Aim for each unit test method to perform exactly one assertion
We should try to test only one thing per test case,so use one single assertion per test case. This way, if some test case fails, you know exactly what went wrong.
6. Create unit tests that target exceptions
If some of your test cases, which expect the exceptions to be thrown from the application, use the “expected” attribute. Try avoiding catching exception in catch blocks and using fail or assert method to conclude these tests.
7. Do not print anything out in unit tests
If you are correctly following all the guidelines, then you will never need to add any print statement in your test cases. If you feel like you need one, revisit your test case(s).
8. Extend from generic classes to avoid rewriting code
Use generic abstract classes (e.g. JdbTemplateDAO
and JpaDAO
) as much as you can when you are mocking database connections
9. Check that the mocked values you are going to create don’t exist already
When mocking values related to the most used entities, check that they don’t already exist on auxiliary classes.
10. Create a Junit suite when testing classes which implement more than one interface
Our test design is interface oriented, so in case a class implements more than one interface, in order to see the coverage more easily we can create suites as seen in this example using the @Suite.SuiteClasses
annotation.
1 |
|