Funrab
Funrab

Reputation: 83

Is it possible to initialize some of the fields in a mock object

I have a code that I cannot correctly cover with tests. I am using the Mockito library. And I had difficulty at the moment of starting the test.

Below is the test code:

@Test
public void testLoadCar() {
    when(remoteService.loadData()).thenReturn(new DataResult<DataCar>("", "", new DataCar()));
    when(dataResult.hasError()).thenReturn(true);
    when(dataResult.response.hasHeaders()).thenReturn(true);
    requestNetwork = new RequestNetwork(remoteService);
    Response<DataCar> response = requestNetwork.load(request);
}

These are objects in the test class: remoteService, dataResult, request.

I am concerned about the moment where I am trying to implement the when method:

when(dataResult.response.hasHeaders()).thenReturn(true);

I would like to know if such a recording will work. If it doesn't work, then how can we handle this moment:

protected Response createResponse(DataResult<T> dataResult) {
    if (dataResult.hasError()  || !dataResult.response.hasHeaders()) {
        return dataResult.getErrorMessage());
    } else {
        return Response.data(dataResult.value);
    }
}

This is a method on the system under test (SUT) that has a createResponse() method. This method contains a call to the mock method of the DataResult object. To implement dataResult.hasError () I got it:

when (dataResult.hasError ()). thenReturn (true);

Then with! DataResult.response.hasHeaders () I have a problem. Since I don't understand how to substitute the value I need.

Upvotes: 1

Views: 1850

Answers (1)

Lesiak
Lesiak

Reputation: 26094

Not all objects that your object under test interacts with need to be mocks. Remember that you can use POJOs as well.

DataResult looks like a perfect candidate for a POJO. You gain nothing by using a mock objet if you can create a POJO with desired state and behaviour.

Looking at the posted code, it looks like it is easy to create:

new DataResult<DataCar>("", "", new DataCar())

On top of that:

Your code looks suspicious to me.

  • when stubbing remoteService.loadData() you create a new instance of DataResult
  • subsequently, you stub some calls on dataResult, which is not an object returned from remoteService.loadData()

And to answer original post:

You can set fields on mocks (directly if access modifiers allow it, or via reflection otherwise). Note that this is highly not-idiomatic and surprising use of mocks.

class A {
    B b;
}

class B {
    boolean hasHeaders() {
        return true;
    }
}

@ExtendWith(MockitoExtension.class)
public class AAATest {

    @Mock
    A aMock;

    @Mock
    B bMock;

    @BeforeEach
    void setupMocks() {
        aMock.b = bMock;
    }

    @Test
    void testFieldInMockIsInitialized() {
        Assertions.assertEquals(bMock, aMock.b);
    }
}

Upvotes: 3

Related Questions