Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito: How to replace method of class which is invoked by class under test?

Unfortunately the Mockito documentation lacks of exhaustive information, it's difficult to find the proper way how to create the following setup.

I have a class "ResourceManager" which should be tested. This class instantiates another class "JerseyClient" which has a method called "get". I want "ResourceManager" to not invoke the real "JerseyClient" but a mock (or a stub?) from it (It's already unclear to me what is the difference between mocking and stubbing or mocks and spies in Mockito context).

My attempts are to @Mock (or @Spy?) JerseyClient, or at least one method of it:

@RunWith(MockitoJUnitRunner.class)
public class ResourceManagerTest
{
    @Mock
    private JerseyClient jerseyClient;


    @Test
    public void testResultHandling() throws JsonGenerationException, JsonMappingException, IOException, ResourceException
    {
        TestEntity testEntity = new TestEntity();
        ResourceManager resourceManager = new ResourceManager();

        testEntity.setGet(true);
        testEntity.setTestAttribute("1stTest");

        when(jerseyClient.get(anyString())).thenReturn("{\"get\":true,\"testAttribute\":\"2ndTest\",\"message\":\"success\"}");

//      doReturn("{\"get\":true,\"testAttribute\":\"2ndTest\",\"message\":\"success\"}").when(jerseyClient).get(anyString());

        TestEntity result = (TestEntity)resourceManager.execute(testEntity, TestEntity.class);

        assertThat(result, is(notNullValue()));
        assertThat(result.getMessage(), is("success"));
        assertThat(result.getTestAttribute(), is("2ndTest"));
    }
}

As you can see, I tried to mock jerseyClient.get() method to return a predefined JSON string:

when(jerseyClient.get(anyString())).thenReturn("{\"get\":true,\"testAttribute\":\"2ndTest\",\"message\":\"success\"}");

or

doReturn("{\"get\":true,\"testAttribute\":\"2ndTest\",\"message\":\"success\"}").when(jerseyClient).get(anyString());

But none of them work. That means that the real JerseyClient.get method is invoked, because it tries to make a HTTP request with the real JerseyClient.

What is the solution and what is this what I want to do here? Is it spying on a real object or mocking an object where I want to mock a method of it, and when can I replace methods, only on mocks or only on spies?

like image 700
Bevor Avatar asked Jun 08 '13 14:06

Bevor


People also ask

How do you mock another method in the same class which is being tested in Java?

Instead of using mock(class) here we need to use Mockito. spy() to mock the same class we are testing. Then we can mock the method we want as follows. Mockito.

Is it possible to call the actual methods after mocking a class?

Mockito allows us to partially mock an object. This means that we can create a mock object and still be able to call a real method on it. To call a real method on a mocked object we use Mockito's thenCallRealMethod().

What is the difference between @mock and @InjectMocks?

@Mock is used to create mocks that are needed to support the testing of the class to be tested. @InjectMocks is used to create class instances that need to be tested in the test class. Annotated class to be tested dependencies with @Mock annotation.

What is stubbing in Mockito?

A stub is a fake class that comes with preprogrammed return values. It's injected into the class under test to give you absolute control over what's being tested as input. A typical stub is a database connection that allows you to mimic any scenario without having a real database.


1 Answers

I found the answer on my own. I need to add

@InjectMocks
private ResourceManager resourceManager;

Then I need to run the test with this instance:

@RunWith(MockitoJUnitRunner.class)
public class ResourceManagerTest
{
    @Mock
    private JerseyClient jerseyClient;

    @InjectMocks
    private ResourceManager resourceManager;

    @Test
    public void testResultHandling() throws JsonGenerationException, JsonMappingException, IOException, ResourceException
    {
        TestEntity testEntity = new TestEntity();

        testEntity.setGet(true);
        testEntity.setTestAttribute("1stTest");

        when(jerseyClient.get(anyString())).thenReturn("{\"get\":true,\"testAttribute\":\"2ndTest\",\"message\":\"success\"}");   

        TestEntity result = (TestEntity)resourceManager.execute(testEntity, TestEntity.class);

        assertThat(result, is(notNullValue()));
        assertThat(result.getMessage(), is("success"));
        assertThat(result.getTestAttribute(), is("2ndTest"));
    }
}

And I can also use the "doReturn...when" pattern.

like image 74
Bevor Avatar answered Sep 16 '22 12:09

Bevor