Hot questions for Using Mockito in code coverage

Top 10 Java Open Source / Mockito / code coverage

Question:

I am mocking JdbcTemplate for unit test cases, as don't want to hit actual database integration.

But it is decreasing my code coverage (Red indicates missing coverage).

Below is the snippet used. Same case happens by using user defined mappers.

final List<String> resultList = new ArrayList<String>();
resultList.add("test1");
resultList.add("test2");
final JdbcTemplate template = Mockito.mock(JdbcTemplate.class);
Mockito.when(
    template.query(Mockito.anyString(), Mockito.any(Object[].class),
        Mockito.any(RowMapper.class))).thenReturn(resultList);
sampleDao.setJdbcTemplate(template);

Any ideas for increasing code coverage in dao class. All methods doesn't suit for user defined row mappers in my case.


Answer:

One way of doing this is as follows:

final List<String> resultList = new ArrayList<String>();
resultList.add("test1");
resultList.add("test2");

final JdbcTemplate template = mock(JdbcTemplate.class);

when(template.query(anyString(), any(Object[].class), any(RowMapper.class)))
    .thenAnswer(new Answer<List<String>>() {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            // Fetch the method arguments
            Object[] args = invocation.getArguments();

            // Fetch the row mapper instance from the arguments
            RowMapper<String> rm = (RowMapper<String>) args[2]; 

            // Create a mock result set and setup an expectation on it
            ResultSet rs = mock(ResultSet.class);
            String expected = "value returned by query";
            when(rs.getString(1)).thenReturn(expected);

            // Invoke the row mapper
            String actual = rm.mapRow(rs, 0);

            // Assert the result of the row mapper execution
            assertEquals(expected, actual);

            // Return your created list for the template#query call
            return resultList;
        }
    });

But as you can see, it's a lot of code to test the row mapper :)

Personally, I would prefer going with an integration test OR moving the row mapper to a class of its own and unit testing it separately.

Question:

These libraries are loaded:

  • JUnit 5.3.2
  • JaCoCo 0.8.2
  • Mockito 2.10.0

Only element "static {...}" appears with 100% coverage. All the rest is at 0%:

The unit test class has annotations @ExtendWith(SpringExtension.class) and @AutoConfigureMockMvc. The service is injected with @Mock.

doReturn(actual).when(service).get(param);
when(service.get(param)).thenReturn(actual);

expected = service.get(param);
verify(service, times(1)).get(param);

assertEquals(expected, actual);
assertEquals(actual, expected);

My ServiceImpl class is red when I click any method. It extends an abstract class. Jackson's ObjectMapper is red, and also the entire lines within the methods. For example:

public CustomReturnObject get(final CustomParamObject paramObject) {
    try {
        return retryTemplate.execute(status -> {
            String json = repository.get(paramObject);
            CustomReturnObject returnObject = json2CustomObject(json, paramObject);

            if (returnObject == null) {
                returnObject = new CustomReturnObject();
                returnObject.setId(paramObject.getId());
            }

            return returnObject;
        });
    } catch (Exception ex) {
        log.error(ex.getMessage(), ex);
        return null;
    }
}

Answer:

Similarly to https://stackoverflow.com/a/46614216/244993 let's put aside Spring, because there is IMO clearly something wrong with your expectations/understanding about core thing here - mocking.

By

doReturn(actual).when(service).get(param);
expected = service.get(param);
verify(service, times(1)).get(param);
assertEquals(expected, actual);

you are not testing get method, you are testing something that always returns actual, no matter what is actually written in get, because in this case it is not executed.

Here is complete example as a proof:

src/main/java/hello/GreetingService.java:

package hello;

class GreetingService {

  Object get(Object param) {
    throw new UnsupportedOperationException();
  }

}

src/test/java/hello/GreetingServiceTest.java:

package hello;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;

@ExtendWith(MockitoExtension.class)
public class GreetingServiceTest {

  @Mock
  public GreetingService service;

  @Test
  void test() {
    Object param = new Object();
    Object actual = new Object();

    doReturn(actual).when(service).get(param);
    Object expected = service.get(param);
    verify(service, Mockito.times(1)).get(param);
    assertEquals(expected, actual);
  }

}

build.gradle :

apply plugin: 'java'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    testCompile 'org.mockito:mockito-junit-jupiter:2.23.4'
}

Real method get throws UnsupportedOperationException, however above test succeeds, so real method was not executed. As another way to proof that get not executed: put a breakpoint into it and execute test in debug mode from IDE - breakpoint won't be reached.

Coverage shows what was really executed and hence absolutely correct that it is zero for methods that are not executed.