Search code examples
javajunitmockitoabstract-class

Junit test cases for a method in Abstract Class which calls a method of its non-abstract Super class


I have a Parent Class Parent

    class Parent{
        public String calculate(String input){
           // does lots of external system calls and complex calculations
        }
    }

Then I have an Abstract Class which extends the parents.

public abstract class AbsChild extends Parent{
    
    public String calculatePayments(String abc, String xyz){
       
        String ZXC = doSomething(abc);
        // more code
    }
    
    private String doSomething(String abc){
       
        String STR = super.calculate(abc);
        // more code
    }
}

Now I need to write a test case for this calculatePayments method. I mocked the super.calculate(abc) but it stills call the real method and throws exception. Here's what I tried.

public class AbsChildTest extends AbsChild{

     @Test
     public void testCalculatePayments(){
   
         Parent parent = mock(Parent.class);
         when(parent.calculate(anyString())).thenReturn("str");
         this.calculatePayments("abc", "xyz");

     }

}

This always calls the real method which has calls to lots of external systems. Can it be achieved without using PowerMock.


Solution

  • This doesn't work because 'this' object, in your code, translates to the JVM calling the super method calculate() on behalf of 'this'. And 'this' is a real object and not a mock, leading to the real method being called.

    Also, I must say that this is a sign you need to restructure your original code.

    But in case you're dealing with 'legacy code' which can't be changed, you need to inject your mock into the execution somehow. Below is a working, but sketchy example using a wrapper as the System Under Test instead :

    public class AbsChildTest {
    
        // System Under Test (sut)
        private class AbsChildWrapper extends AbsChild {
            // provide methods and constructors from AbsChild required to be overidden
        }
    
        @Test
        public void testCalculatePayments(){
    
            AbsChildWrapper sut = Mockito.spy(new AbsChildWrapper());
            Mockito.when(sut.calculate(ArgumentMatchers.anyString())).thenReturn("str");
    
            String result = sut.calculatePayments("abc", "xyz");
            Assertions.assertEquals("str", result);
        }
    
    }