Search code examples
javaspringmockitojunit4

Mockito NullPointerException From Super Class Method Call


I have the following stripped down classes (let's pretend the Service interface just has the single overriden method for simplicity). No matter what I try, I always get a NullPointerException when the ServiceImpl calls getSqlSession() . How can I override this call to avoid the exception? I have tried creating a spy ServiceImpl and calling when on the method getSqlSession(), but I still get the exception. I do not want to put the logic within ServiceImpl.getData() that changes the List<Object> into a Map<String,Object> into the test class since if this implementation ever changes, the test code needs to be changed also. Any suggestions?

public class ServiceImpl extends BaseService implements Service {

    @Autowired
    private ServiceDAO serviceDao;

    @Override
    public Map<String, Object> getData() {
        Map<String,Object> map = new HashMap<String,Object>();
        List<Object> resultSet = service.getData(getSqlSession());
        map.put("Test", resultSet.get(0));
        map.put("Test2", resultSet.get(1));

        return map;
    }

   public void setServiceDao(final ServiceDAO serviceDao) {
     this.serviceDao = serviceDao;
   }

}

The BaseService:

public class BaseService {

    @Autowired
    private ApplicationContext context;

    public SqlSession getSqlSession() {
        return (SqlSession)context.getBean("SQL_SESSION");
    }

    public void setContext(ApplicationContext context) {
        this.context=context;
    }

}

The DAO

public class ServiceDAO {
    public List<Object> getData(SqlSession sqlSession) {
        return sqlSession.selectList("proc_name");
    }
}

And the Test Class:

public class ServiceImplTest {

    private Service service;

    @Mock
    private ServiceDAO serviceDao;

    @Before
    public void before() {
        MockitoAnnotations.initMocks(this);
        service = new ServiceImpl();
        service.serviceDao = this.serviceDao;
    }

    @Test
    public void testGetData() {
        Mockito.when(service.getData()).then(new Answer<List<Object>>() {

        @Override
        public List<Object> answer(InvocationOnMock invocation) throws Throwable {
            return serviceDAO.getData(new DefaultSqlSession(null,null));

        }

    });

        service.getData();

    }
}

Solution

  • Was finally able to get this working with below test class. Had to change the Service declaration from the Interface to the actual Impl class. Not sure if there is any way around this as all other attempts have not worked.

    public class ServiceImplTest {
    
        @Mock
        private ServiceDAO serviceDAO;
    
        @Spy
        private ServiceImpl service;
    
        @Before
        public void before() {
            MockitoAnnotations.initMocks(this);
            //service = new ServiceImpl();
            service.setServiceDAO(this.serviceDAO);
        }
    
        @Test
        public void testGetData() {
            Mockito.doAnswer(new Answer<SqlSession>(){
    
                @Override
                public SqlSession answer(InvocationOnMock invocation) throws Throwable {
                    return new DefaultSqlSession(null,null);
                }
    
            }).when(service).getSqlSession();
    
            Mockito.when(service.getData()).then(new Answer<List<Object>>() {
    
            @Override
            public List<Object> answer(InvocationOnMock invocation) throws Throwable {
                return serviceDAO.getData(new DefaultSqlSession(null,null));
    
            }
    
        });
    
            service.getData();
    
        }
    
    }