1
votes

I am using Mockito services to test the Exception that could be thrown in MyFinalClass and be caught in MyAbstractClass as the concrete method makes a call to the getObject method in MyFinalClass.

Please see below code.

public abstract class MyAbstractClass{

    @Autowired
    private MyFinalClass myFinalClass;

    //concrete method
    protected Object myConcreteMethod(String name){
        try{
            Object b = myFinalClass.getObject(name);
            return b;
        } catch(MyException e){
          LOGGER.log("ERROR THROWN" + e);
        }
    }

}

public final class MyFinalClass {

    public Object getObject(String name) throws MyException{
        **** HAS NOT YET BEEN IMPLEMENTED ****
        return null;
    }

}

public MyException extends Exception{
    ....
}

Below is the test class I have written. Unfortunately I am having issues with Mockito.when(myFinalClass).getObject(name).thenReturn(Mockito.mock(Object.b)), as it does not seem to get called.


@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
@RunWith(PowerMockRunner.class)
public class MyAbstractClassTest  {

    public static class ExampleConcreteClass extends MyAbstractClass{

    }

    @InjectMocks
    ExampleConcreteClass exampleConcreteClass;

    @Mock
    MyFinalClass myFinalClass;

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

    @Test
    public void testMyConcreteMethod(){
        try{
           Mockito.when(myFinalClass).getObject(name). 
           thenThrow(new MyException()); 

           exampleConcreteClass.myConcreteMethod();
           Assert.fail();
        }catch(MyException e){
           Assert.assertTrue(Boolean.TRUE);
        }
    }

}

Because the implementation has not yet been completed for the getObject(String name) method in MyFinalClass, I am throwing new MyException() on the call of the getObject method. However the exception does not get thrown as the Mockito.when(...) call does not get called, causing Assertion to fail.

Please help. Thank you.

1

1 Answers

2
votes

Mockito is not able to mock out final classes. There are a few ways to get around this.

1) In MyAbstractClass consider not referencing a final class, and instead reference an interface or abstract class that MyFinalClass implements (or extends). So lets say that MyFinalClass implements an interface called MyGettableApi. Then MyAbstractClass would look like this.

 public abstract class MyAbstractClass{

    @Autowired
    private MyGettableApi gettableService;

    //concrete method
    protected Object myConcreteMethod(String name){
        try{
            Object b = gettableService.getObject(name);
            return b;
        } catch(MyException e){
          LOGGER.log("ERROR THROWN" + e);
        }
    }

}  


public final class MyFinalClass implements MyGettableApi {

    @Override
    public Object getObject(String name) throws MyException{
        **** HAS NOT YET BEEN IMPLEMENTED ****
        return null;
    }

}


public interface MyGettableApi {
    public Object getObject(String name);
}

Now in your test code you can mock out MyGettableApi, since it is not final, without a problem.

    @Mock
    MyGettableApi myFinalClass;

2) Another way around this is wrap the call to myFinalClass.getObject(name); wrapped in another method.

public abstract class MyAbstractClass{

    @Autowired
    private MyFinalClass myFinalClass;

    //concrete method
    protected Object myConcreteMethod(String name){
        try{
            Object b = myGetObjectWrapperMethod(name);
            return b;
        } catch(MyException e){
          LOGGER.log("ERROR THROWN" + e);
        }
    }

    Object myGetObjectWrapperMethod(String name) {
        return myFinalClass.getObject(name);
    }

}

Now in your test code you would @Spy the instance of MyAbstractClass that is being tested.

@InjectMocks
@Spy
ExampleConcreteClass exampleConcreteClass;

then you can mock out our new wrapper method.

doThrow(new MyException()).when(exampleConcreteClass).myGetObjectWrapperMethod(name);