I am getting this exception - java.lang.IllegalArgumentException: No serializer found for class org.mockito.internal.creation.bytebuddy.ByteBuddyCrossClassLoaderSerializationSupport and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.mockito.codegen.Object$MockitoMock$["mockitoInterceptor"]->org.mockito.internal.creation.bytebuddy.MockMethodInterceptor["serializationSupport"])
The Testcase I'm writing looks like this
@Mock
Object object;
@Mock
ResponseType response;
@Test
public void handleRequest() {
ObjectMapper mapper = new ObjectMapper();
when(mapper.convertValue(object, ResponseType.class)).thenReturn(response)
new Handler().handleRequest(object);
}
The method I'm trying to test:
public class Handler{
public ResponseType handleRequest(Object object) {
ObjectMapper mapper = new ObjectMapper();
ResponseType response = mapper.convertValue(object, ResponseType.class);
return response;
}
}
I see that I can disable SerializationFeature.FAIL_ON_EMPTY_BEANS, but I have no control over the base class, I can only write a test case. Can someone tell me what I am doing wrong and what I can add to the test case? I cannot instantiate an ObjectMapper within the testcase as it has to be a mock, and I tried using a spy on the ObjectMapper and disable the SerializationFeature.FAIL_ON_EMPTY_BEANS, but neither works. I am also pretty new to Mockito so I'm not sure how I can proceed further. Any help would be appreciated, thanks
CodePudding user response:
There are two problems with your test code. You're calling the real ObjectMapper method instead of mocking it (1) and you're not using the created object (even though it's not a mock) in your actual code (2).
In the lines below (I've added newlines and a comment, but it's the same as your code) you're creating an instance of ObjectMapper
(not a mock) and while trying to mock it's behavior, you're actually calling the real method of the created object:
ObjectMapper mapper = new ObjectMapper();
when(
// here an actual convertValue method is called on the mapper object
// which causes the exception you're getting
mapper.convertValue(object, ResponseType.class)
).thenReturn(response)
If you used a method that's not calling the actual method while mocking (useful when working with spies):
doReturn(response)
.when(mapper)
.convertValue(object, ResponseType.class);
you'd still get an error, but this time it would be:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!
Example of correct stubbing:
doThrow(new RuntimeException()).when(mock).someMethod();
That's because the mapper
you're creating is not a Mockito mock/spy, so it cannot be mocked. To fix that you need to use the mock(...)
method or the @Mock
annotation (remember to initialize/open them):
ObjectMapper mapper = mock(ObjectMapper.class);
when(mapper.convertValue(object, ResponseType.class))
.thenReturn(response);
Now neither the initial error (that you were getting) nor NotAMockException
are thrown, but the mocking has no effect.
In your actual code here:
public ResponseType handleRequest(Object object) {
ObjectMapper mapper = new ObjectMapper();
...
}
you're creating ObjectMapper
using new
. This object is in no way connected to the mock that is created in the test - it is not injected. To fix that, it would be best to store the ObjectMapper
instance in a field and initialize it with the class creation (injection) - both in the actual code and in the tests:
class Handler {
private ObjectMapper objectMapper;
Handler(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
public ResponseType handleRequest(Object object) {
// use the objectMapper here
}
}
Thanks to that you can pass the mocked ObjectMapper
in the test to the tested object constructor:
@Test
public void handleRequest() {
ObjectMapper mapper = mock(ObjectMapper.class);
when(mapper.convertValue(object, ResponseType.class)).thenReturn(response);
new Handler(mapper).handleRequest(object);
}
Other ways of doing that could be using a factory providing the ObjectMapper
, also mocked in the tests, or (not recommended) using mockito-inline with it's mockConstruction method (since Mockito 3.5.0).