I am trying to write unit test using Powermockito for following method -
public String getGenerator(String json) throws IOException {
String jwt = "";
ObjectMapper mapper = new ObjectMapper();
// convert JSON string to Map
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>() {
}); // Here passing TypeReference annonymously
// Create a JWT
JWTGenerator generator = new JWTGenerator();
if (map != null && map.size() > 0) {
jwt = generator.createJWT(map);
}
return jwt;
}
I have written test method as -
@Test
public void testGetJWTGenerator() throws Exception {
ObjectMapper mockMapper = PowerMockito.mock(ObjectMapper.class);
PowerMockito.whenNew(ObjectMapper.class).withNoArguments().thenReturn(mockMapper);
JWTGenerator mockJWTDecoder = PowerMockito.mock(JWTGenerator.class);
PowerMockito.whenNew(JWTGenerator.class).withNoArguments().thenReturn(mockJWTDecoder);
Map<String, Object> anyMap = new HashMap<String, Object>();
anyMap.put("testStr", new Object());
TypeReference<Map<String, Object>> mockTypeReference = (TypeReference<Map<String, Object>>) PowerMockito.mock(TypeReference.class);
PowerMockito.whenNew(TypeReference.class).withNoArguments().thenReturn(mockTypeReference);
PowerMockito.when(mockMapper.readValue(Mockito.anyString(), Mockito.eq(mockTypeReference))).thenReturn(anyMap);
PowerMockito.when(mockJWTDecoder.createJWT(anyMap)).thenReturn(Mockito.anyString());
utilityController = new UtilityController();
utilityController.getJWTGenerator("{\"someStr\":\"someStr\"}");
Mockito.verify(mockJWTDecoder, Mockito.times(1)).createJWT(anyMap);
}
When I run this test I always get it failed saying -
Wanted but not invoked:
jWTGenerator.createJWT(
{testStr=java.lang.Object@24bdb479}
);
It looks like stub is not working as I always get "null" for this line -
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>() {
}); // Here passing TypeReference annonymously
Is it because anonymous instantiation of TypeReference class?
Yes, it's because of the anonymous inner class. Specifically, you tell PowerMockito to replace the call to new TypeReference
:
PowerMockito.whenNew(TypeReference.class).withNoArguments()
.thenReturn(mockTypeReference);
But what you're actually creating is an anonymous class that extends TypeReference, not a TypeReference itself:
Map<String, Object> map = mapper.readValue(
json, new TypeReference<Map<String, Object>>() {});
This is going to be especially tricky for you. My normal advice here is "don't mock data objects" like TypeReference, because it's a no-dependency token/value/data object that works heavily on reflection, but it also doesn't support equals
the way its cousins in Guice and Guava do; unlike with Guice and Guava you couldn't just create your own real TypeReference in your test and match with Mockito's eq
.
You still shouldn't mock TypeReference, but you'll also need to adjust how you assert against it:
isA
to check its type.Captor
and check the TypeReference's generic type using getType
.ArgumentMatcher
implementation that uses getType
and consume it with argThat
.ArgumentMatchers.any()
or ArgumentMatchers.<TypeReference<Map<String, Object>>>any()
, which was previously on the Matchers
and Mockito
interfaces. The value is unlikely to change anyway, so pragmatically your system and test may be more readable and robust from disregarding the check than from convincing PowerMock otherwise.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With