13

I'm testing a service layer and not sure how to mock ObjectMapper().readValue in that class. I'm fairly new to mockito and could figure out how to do it.

The following is my code,

service.java

private configDetail fetchConfigDetail(String configId) throws IOException {
    final String response = restTemplate.getForObject(config.getUrl(), String.class);
    return new ObjectMapper().readValue(response, ConfigDetail.class);
}

ServiceTest.java

@Test
public void testgetConfigDetailReturnsNull() throws Exception {

    restTemplate = Mockito.mock(restTemplate.class);
    Service service = new Service();
    Config config = Mockito.mock(Config.class);
    ObjectMapper objMapper = Mockito.mock(ObjectMapper.class);
            Mockito.doReturn("").when(restTemplate).getForObject(anyString(), eq(String.class));
    Mockito.doReturn(configDetail).when(objMapper).readValue(anyString(),eq(ConfigDetail.class));
    assertEquals(configDetail, service.getConfigDetail("1234"));
}

I get the following results when I run this test,

com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: (String)""; line: 1, column: 0]

Posting ServiceTest.Java here

@RunWith(MockitoJUnitRunner.class)
public class ConfigServiceTest {

    @Mock
    private ConfigPersistenceService persistenceService;

    @InjectMocks
    private ConfigService configService;

    @Mock
    ConfigDetail configDetail;

    @Mock
    private RestTemplate restTemplate;

    @Mock
    private ObjectMapper objMapper;

    @Mock
    private Config config;

    @Test
    public void testgetConfigDetailReturnsNull() throws Exception {

        ObjectMapper objMapper = Mockito.mock(ObjectMapper.class);
        Mockito.doReturn(ucpConfig).when(persistenceService).findById("1234");

        Mockito.doReturn("").when(restTemplate).getForObject(anyString(), eq(String.class));

        Mockito.when((objMapper).readValue(“”,ConfigDetail.class)).thenReturn(configDetail);
        assertEquals(ConfigDetail, ConfigService.getConfigDetail("1234"));
    }
}
Panch
  • 1,097
  • 3
  • 12
  • 43
  • Please explain why this question was downvoted I reckon that would help me to understand whats not right here. – Panch Feb 03 '18 at 23:20

4 Answers4

4

Problem is with the this line where you are mocking the call to objectmapper.

Mockito.when((objMapper).readValue(“”,ConfigDetail.class)).thenReturn(configDetail);

Correct syntax is

Mockito.when(objMapper.readValue(“”,ConfigDetail.class)).thenReturn(configDetail);

Notice the bracket position. When using Spy or Verify, the bracket position is diff. then when using when-then syntax.

lrathod
  • 1,094
  • 1
  • 9
  • 17
2

With your current Service class it would be difficult to mock ObjectMapper, ObjectMapper is tightly coupled to fetchConfigDetail method.

You have to change your service class as follows to mock ObjectMapper.

@Service
public class MyServiceImpl {

    @Autowired
    private ObjectMapper objectMapper;

    private configDetail fetchConfigDetail(String configId) throws IOException {
        final String response = restTemplate.getForObject(config.getUrl(), String.class);
        return objectMapper.readValue(response, ConfigDetail.class);
    }
}

Here what I did is instead of creating objectMapper inside the method I am injecting that from outside (objectMapper will be created by Spring in this case)

Once you change your service class, you can mock the objectMapper as follows.

ObjectMapper mockObjectMapper = Mockito.mock(ObjectMapper.class);
Mockito.when(mockObjectMapper.readValue(anyString(), any(ConfigDetail.class)).thenReturn(configDetail);
Jobin
  • 5,610
  • 5
  • 38
  • 53
  • I did follow the steps as advised here but still running into the same issue. I still see the `objectMapper.readValue(response, ConfigDetail.class)` invoked and please find the call stack as below, `at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59) at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4133) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3988) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)` – Panch Feb 03 '18 at 11:37
  • 1
    am I still missing anything here? the expectation here is that the `return objectMapper.readValue(response, ConfigDetail.class);` should not be invoked at all rather simply return the value as mocked in here `Mockito.when(mockObjectMapper.readValue(anyString(), any(ConfigDetail.class)).thenReturn(configDetail); `. Please advise. – Panch Feb 03 '18 at 11:41
  • Post the complete test class – Jobin Feb 03 '18 at 11:42
  • With that mapper it wouldn't work because the signature of readValue requires a "Class.class" and you are giving a ConfigDetail.class. What would be correct, I know there was a matcher for it but I don't remember where... – Gonzalo Aguilar Delgado Nov 14 '19 at 10:48
  • ObjectMapper is not a bean so how do I autowire it? – DaithiG Oct 22 '21 at 17:50
1

Mocking objects created in a SUT is IMO the single biggest limitation of mockito. Use jmockit or powerMock or checkout the offical mockito way of handling this. https://github.com/mockito/mockito/wiki/Mocking-Object-Creation

Jacob Botuck
  • 411
  • 6
  • 22
0

If you are using junit 5, below line mocks the Objectmapper readvalue(String, Class) method. To avoid ambiguity in the readValue method, we are using typecasting.

@Mock
ObjectMapper objMapper;
Mockito.when(objMapper.readValue((String)Mockito.any(),Mockito.any(Class.class))).thenReturn(configDetail);
Devi
  • 1
  • 1