loading...
Cover image for Mock a Mockito

Mock a Mockito

angelesbroullon profile image Angeles Broullón Originally published at mangelesbroullon.wordpress.com ・10 min read

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.

The server layered model: Service layer -> Business  layer -> DataAccess layer -> Database, the first 3 are tagged as Java code

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

<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.12</version>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.mockito</groupId>
   <artifactId>mockito-all</artifactId>
   <version>1.9.5</version>
   <scope>test</scope>
</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.

@Local
public interface IDocumentAccessDao extends IJdbcTemplateDao{
  void getCollaborateDocumentStatus() throws GenericDAOException;
}

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.

<!- DATAACCESS-DAO ->
<context:component-scan base-package="org.mydomain.app.dataaccess.dao.impl" />
<!- DATAACCESS-DAO-MOCKITO ->
<context:component-scan base-package="org.mydomain.aap.dataaccess.mocked" />

Now let’s check the class we are going to test:

@Repository
@Qualifier("DocumentAccessDAO")
@Stateless(name = "DocumentAccessDAO")
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Interceptors({ SpringBeanAutowiringInterceptor.class })
public class DocumentAccessDAO extends AbstractJdbcTemplateDAO implements
 IDocumentAccessDAO {

 @EJB
 private DocumentDAO documentDAO;
 private DocumentAccessRowMapper dmRowMapper = new DocumentAccessRowMapper();
 private DocumentAccessPreparedStatementSetter dPreparedStatementSetter
  = new DocumentAcccessPreparedStatementSetter();

 @Override
 public List<Document> getCollaborateDocumentStatus() throws GenericDAOException {
  List<Document> listDocs = new LinkedList<Document>();
  try {
   List<Map<String, Object>> resultSet = this.jdbcTemplate.queryForList(
       SqlDocumentManager.COLL_DOCUMENT_STATUS);
   if (!CollectionUtils.isEmpty(resultSet)) {
    for (Map<String, Object> data : resultSet) {
     String docId = String.valueOf(data.get("DOCID"));
     int version = documentDAO.getLastDocumentVersion(docId);
     Document document = documentDAO.getDocumentVersion(docId, version, null);
     listDocs.add(document);
    }
   }
  } catch (DataAccessException e) {
   throw new GenericDAOException(e);
  }
  return listDocs;
 }
}

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 in DocumentAccessDAO, 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.
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Interceptors(SpringBeanAutowiringInterceptor.class)
@ContextConfiguration(locations = "/appDao-testConfiguration.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class DocumentAccessDAOTest {
  // all the mocks will be injected into this instance
  @InjectMocks
  private DocumentAccessDAO documentDAO;
  // initialize the mocker via annotation
  @Mock
  private JdbcTemplate jdbcTemplate;
  @Mock
  private DocumentAccessDAO documentDAO;

  @Before
  public void initMock() {
    // initialize generic behaviour
    Mockito.when(jdbcTemplate.queryForList(Matchers.anyString())
      .thenReturn(createResultList());
    Mockito.when(documentDAOMock.getLastDocumentVersion(Matchers.anyString()))
      .thenReturn(1);
    Mockito.when(documentDAO.getDocumentVersion((String)
      Matchers.anyString(), Matchers.anyString(), Matchers.anyString()).thenReturn(
      creatDummyDocument());
  }

  @Test
  public void getCollaborateDocumentStatusReturnsValidResultExpected()
   throws GenericDAOException {
    // method to call
    List<Document> listDocument = managerDAO.getCollaborateDocumentStatus();
    // check result
    Assert.assertTrue(!listDocument.isEmpty() && listDocument.size() == 4
     && listDocument.get(0).getDocId().equals(MockedDocumentValues.MY_DOCUMENT_ID) 
     && listDocument.get(1) == null);
  }

  // the exception is managed through the annotation
  @Test(expected = GenericDAOException.class)
  public void getCollaborateDocumentStatusReturnsxceptionException()
   throws GenericDAOException {
    // initialise non-generic mocked methods for this test
    Mockito.when(jdbcTemplate.queryForList(Matchers.anyString())
     .thenThrow( new RecoverableDataAccessException(MockedValues
       .GENERIC_DAO_EXCEPTION_TEXT));    
    // method to call
    managerDAO.getCollaborateDocumentStatus();
  }

  private Document createDummyDocument(){
    Document document = new Document();
    document.setVersion(1);
    document.setDocId(MockedDocumentValues.MY_DOCUMENT_ID);
    return document;
  }
}

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)
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())
Mockito.when(this.template.update(sql, status, docId))
.thenThrow(new RecoverableDataAccessException(ERROR_CONNECTION_GENERATOR_STRING));

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)
Mockito.doThrow(IOException.class).when(this.em).
persist(Matchers.any(Object.class));

3. Using matchers

  • When we want to return a value independently of the parameters content, we can use Matchers.any(Object.class) (where Object 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() …).
Mockito.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) and Matchers.eq(instance)
Mockito.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.
public <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.

/**
 * Mocks the update done when persisting a LegalDoc in the database
 */
public void initMockForPersistLegalDoc() {
  Mockito.doAnswer(new AssignIdToLegalDocAnswer(LEGAL_ID)).when(em).persist(
    Matchers.any(LegalDoc.class));
}

private class AssignIdToLegalDocAnswer implements Answer<Void> {

  private int legalDocId;
  public AssignIdToLegalDocAnswer(int legalDocId) {
    this.legalDocId = legalDocId;
  }

  @Override
  public Void answer(InvocationOnMock invocation) throws Throwable {
    LegalDoc legalDoc = (LegalDoc) invocation.getArguments()[0];
    legalDoc.setLegalDocId(legalDocId);
    return null;
  }

}

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.

public void initMockForMyProcedure(MyInputOutputObject object1){
  Mockito.doAnswer(new Answer<MyCustomOutputObject>() {
    @Override
    public MyCustomOutputObject answer(final InvocationOnMock invocation)
     throws Throwable {
      // the original argument may be changed, only for this function
      final MyInputOutputObject originalArgument = (invocation.getArguments())[0];
      // we define the ourput parameter value here
      final MyCustomOutputObject returnedValue = new MyCustomOutputObject();
      returnedValue.setValueOutput(new MyCustomOutput());

      return returnedValue;
    }
  }).when(myService).myProcedure(Matchers.any(MyInputOutputObject.class));
}

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.

public <T> void initMockForCreateNamedQueryGetSingleResult(String sqlQuery,
 T returnedObject, boolean shouldFail) {
  Query mockedQuery = Mockito.mock(Query.class);
  if (shouldFail) {
    Mockito.when(mockedQuery.getSingleResult()).thenThrow(new NoResultException());
   } else {
    Mockito.when(mockedQuery.getSingleResult()).thenReturn(returnedObject);
   }
   Mockito.when(this.em.createNamedQuery(sqlQuery)).thenReturn(mockedQuery);
}

public <T> void initMockForCreateNamedQueryGetResultList(String sqlQuery,
 List<T> returnedObject, boolean shouldFail) {
  Query mockedQuery = Mockito.mock(Query.class);
  if (shouldFail) {
    Mockito.when(mockedQuery.getResultList()).thenThrow(new NoResultException());
  } else {
    Mockito.when(mockedQuery.getResultList()).thenReturn(returnedObject);
  }
  Mockito.when(this.em.createNamedQuery(sqlQuery)).thenReturn(mockedQuery);
}

6. Mocking an abstract class

Abstract classes can be instanced as normal ones by mocking them with CALL_REAL_METHODS.

public void initMockers() {
  dao = Mockito.mock(AbstractDocumentDAOImpl.class, Mockito.CALLS_REAL_METHODS);
  dao.setEntityManager(jpaMocker.getEntityManager());
}

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.

public void initMockForGetMap(Map<String, ?> expectedValue) {
  Mockito.doReturn(expectedValue).when(getter).getMap(Matchers.anyString(),
   Matchers.anyString());
}

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()

public void initMockForQueryForList(List<String> expectedvalue){
  Mockito.when(this.template.queryForList(Matchers.anyString(),
   Matchers.<Object>anyVararg())).thenReturn(expectedValue);
}

Mockito limitations

  1. Mockito can’t mock final classes
  2. Mockito can’t mock static methods
  3. 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.

public final class SendMailHelper{
  // this way we make sure we have only one instance
  private static SendMailHelper instance;

  // no one external can create new instance
  private SendMailHelper(){
  }

  //we control here the instance creation
  public static SendMailHelper getInstance(){
    if (instance == null){
      instance = new SendMailHelper();
    }
    return instance;
  }

  // just in case we need to set a mocker
  public void setMailHelper(SendMailHelper helper){
    instance = helper;
  }

}

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).

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):

EmployeeTest.createWhithNullIdShouldThrowException();
EmployeeTest.createWithNegativeIdShouldThrowException();
EmployeeTest.createWithDuplicateIdShouldThrowException();
EmployeeTest.createWithValidIdShouldPass();

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.

@RunWith(Suite.class)
@Suite.SuiteClasses({ DocumentIDocumentLocalTest.class, DocumentIDocumentTest.class })
  public class DocumentBeanTestSuite {
}

Posted on by:

angelesbroullon profile

Angeles Broullón

@angelesbroullon

Programming while listening to power metal. Amateur doodler. Free software and comic books lover.

Discussion

pic
Editor guide