Skip to content
Advertisement

Getting a No Serializer Found for class when trying to test a method with ObjectMapper

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

Advertisement

Answer

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

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement