Harish
Harish

Reputation: 1273

How to mock an object which is created inside a method which is under test only with mockito not with powermockito?

I have been practising Junit to write the test cases and came across Mockito with which I can mock the dependency objects. So I have written a sample code to test it's behaviour.

I have two classes Sample and Second.

Second class has a simple method which just returns a string which is passed as a parameter to this method

public class Second{
    public String show(String y ){
        return y
    }
}

Now there is a Sample class where I called this show method inside Sample classe's method and returning the string.

public class Sample{
    public String sampleMethod(){
        Second s = new Second();
        return s.show("This should not be displayed");
    }
}

Now I'm testing the Sample class hence I have created a file naming SampleTest

public class SampleTest{
    @Mock
    Second s;

    @InjectMocks
    Sample s = new Sample();

    @Before
    public void setUp(){
        MockitoAnnotations.initMocks(this);
        when(s.show(any(String.class))).thenReturn("This should be displayed");
    }

    @Test
    public void sampleMethodTest(){
        assertEquals("This should be displayed", s.sampleMethod());
    }
}

Now as the Second classes object is created and its method is being called inside the Sample method, I have Mocked the Second class and Injected the mocks into Sample.

Then inside the Before method I have written when and thenReturn statements which will be :

when show method is called inside the second object then I returned my desired outpput which is "This should be displayed"

But the output is not what I expected instead of calling the when and thenreturn statements, the real show method inside the Second object is called.

I'm not able to mock the object which is created the method.

How do I do that?

And I need to be done only with mockito not with powermockito

Upvotes: 1

Views: 13939

Answers (1)

Nkosi
Nkosi

Reputation: 247571

Sample is tightly coupled to Second by creating it within the method under test.

Given the currently stated limitations,

And I need to be done only with mockito not with powermockito

Mockito will not be able to mock the Second used within the Sample.

If Sample can be refactored to follow a more SOLID design like Explicit Dependency Principle via constructor injection.

public class Sample {

    private final Second second;

    public Sample(Second second) {
        this.second = second;
    }

    public String sampleMethod(){
        return s.show("This should not be displayed");
    }
}

Then the dependency would be able to be mocked and injected into the subject class under test

public class SampleTest {
    @Mock
    Second second;

    @InjectMocks
    Sample sample; //second will be injected here

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);            
    }

    @Test
    public void sampleMethodTest() {
        //Arrange
        String expected = "This should be displayed";
        when(second.show(any(String.class))).thenReturn(expected);

        //Act
        String actual = sample.sampleMethod();

        //Assert
        assertEquals(expected, actual);
    }
}

Note the changes to the test so that it behaves as expected when exercised.

If you can't refactor Sample, powerMockito can mock the class initialization.

While powerMockito allows such things, it facilitates poor design choices and code smells like tight coupling, which makes the code difficult to maintain and to test in isolation.

Upvotes: 1

Related Questions