Search code examples
javaunit-testingmockitopowermockito

Unable to properly mock method call when called from inside another class method


MyClass firstClass = PowerMockito.spy(new MyClass());

AnotherClass secondClass;
secondClass = PowerMockito.mock(AnotherClass.class);
PowerMockito.when(secondClass.anotherFunction(Mockito.any()).thenReturn(1);

int myInt = firstClass.myFunction();

if (myInt == 1) {
    System.out.println("true");
}

myFunction calls anotherFunction and returns the results of anotherFunction.

But it's not returning 1 and printing "true" like I would expect, instead it's still doing its real functionality.

What am I missing here?


Solution

  • An instance of AnotherClass is created inside myFunction then the instance is used to call secondClass.anotherFunction from inside myFunction.

    Right. That means that the real instance is used, not the mock. The method under test is tightly coupled to the dependency because it creates a real instance on its own

    public class MyClass {
    
        public int myFunction() {
            AnotherClass secondClass = new AnotherClass();
    
            int result = secondClass.anotherFunction(someValue);
    
            //...
    
            return result;
        }    
    }
    

    How can I use the mocked instance instead?

    You either refactor to have the second class injected, either via constructor or method parameter, which is a clean code design or you use powermock to mock the initialization of the second class, which in my opinion is poor design.

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(MyClass.class) //<-- you must prepare the class creating the new instance
    public class MyClassTest {
        @Test
        public void test() {
            //Arrange
            int expected = 1;                          
            //Mock second class
            AnotherClass secondClass;
            secondClass = PowerMockito.mock(AnotherClass.class);
            PowerMockito.when(secondClass.anotherFunction(Mockito.any()).thenReturn(expected);
    
            //mocking initialization of second class withing first class
            PowerMockito.whenNew(AnotherClass.class).withNoArguments().thenReturn(secondClass);
    
            MyClass firstClass = new MyClass();
    
            //Act
            int actual = firstClass.myFunction();
    
            //Assert                
            assertEquals(expected, actual);
        }
    }
    

    Reference How to mock construction of new objects