Java – Is it really a bad practice to mock a POJO (value object) if you don’t care about what it contains

javamockingtddvalue-object

In the advice of Mockito about how to write good tests, it is written that we should not mock value objects (https://github.com/mockito/mockito/wiki/How-to-write-good-tests#dont-mock-value-objects). They even say

Because instantiating the object is too painful !? => not a valid
reason.

But I don't understand. What if we really don't care about what that object contain?
Let's just say that I have a value object class "Foo" that doesn't have simple constructors (it has an all-args constructor and contains objects that also need all-args constructors).
Let's also say I have the following service:

public class MyService {
    private SomeService someService;
    private OtherService otherService;

    public void myAwesomeMethod() {
        Foo foo = someService.getFoo();
        someOtherService.doStuff(foo);
    }
}

And I need to test that method. Clearly here I don't care about what foo contains because I just pass it to another method. If I want to test it should I really create a foo object with nested constructors/builders? For me it would be really easy to mock foo even if it is a POJO :

public class MyServiceTest {
    @InjectMocks
    MyService myService;

    @Mock
    private SomeService someService;

    @Mock
    private OtherService otherService;

    @Test
    public void testMyAwesomeMethod() {
        Foo mockedFoo = Mockito.mock(Foo.class);

        Mockito.when(someService.getFoo()).thenReturn(mockedFoo);

        Mockito.verify(otherService).doStuff(mockedFoo);
    }

}

But then it wouldn't respect the guidelines given by Mockito. Is there another alternative?

Best Answer

Stubs (that you've called mocks in your question) exist for a reason: they make it possible to replace business code from the classes you depend on in the method you're testing by some very basic statements which provide enough data for the tested method. Mocks, just like stubs, replace business logic by custom logic required for the tests.

  • If a POJO doesn't have business code (i.e. if it's also a data object), stubs and mocks would be useless. Using such data objects in tests should be quite easy. If the method needs a data object in input, just create one in the test.

    Some data objects may be very large, containing dozens of properties. In some languages, you can partially initialize a data object by setting only the properties you need during the test; in other languages, you need to fully initialize it. If this is your case, creating a simple static method which creates the data object with the default values and reusing this method all over the tests could be a solution.

  • If a POJO contains business code, you should isolate your unit tests from it, like you would do for any other class. Here, stubs and mocks are fine, and it doesn't make a difference if the mocked object is a POJO or something else.

Related Topic