Can you mock a non-stationary method that calls a static method using Mockito?
I understand that you cannot mock static methods using mockito. But the method I'm trying to mock is not static, but there is a call to static methods in it. Can I mock this method?
I am getting an exception when I run the test. Is the call to a static method causing this exception?
Class for testing:
public class MyAction{
public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
MyService service = new MyService();
**form.setList(service.getRecords(searchRequest));**
}
}
Dedicated class and method:
public class MyService{
public List getRecords(SearchRequest sr){
List returnList = new ArrayList();
MyDao dao = DAOFactory.getInstance().getDAO();---->Call to static method
// Some codes
return returnList;
}
}
Class with static method:
public class DAOFactory{
private static DAOFactory instance = new DAOFactory();
public static DAOFactory getInstance() {------> The static method
return instance;
}
}
My test:
@Test
public void testSearch() throws Exception{
MyService service = mock(MyService.class);
MyAction action = new MyAction();
List<MyList> list = new ArrayList<MyList>();
when(service.getRecords(searchRequest)).thenReturn(list);
ActionForward forward = action.search(mapping, form, request, response);
}
This is the stack trace when the test is running. Please keep in mind that I have changed the class names for simplicity.
source to share
The problem is that your method search
cannot use the service layout because it creates its own instance MyService service = new MyClass();
. Therefore, you must refactor the class MyAction
to allow MyService
injection and inject layout into it. Or use a heavier weapon - PowerMock.
The easiest and safest refactoring
Use the "extract method" in your IDE repository to extract the "new MyClass ()" construct. So it will be:
public class MyAction{
public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
MyService service = getMyService();
**form.setList(service.getRecords(searchRequest));**
}
MyService getMyService() {
return new MyClass();
}
}
then in unit test you can inject mock by creating an inner subclass:
public class MyActionTest {
private MyService service = mock(MyService.class);
private MyAction action = new MyAction(){
@Override
MyService getMyService() {return service;}
};
@Test
public void testSearch() throws Exception{
List<MyList> list = new ArrayList<MyList>();
when(service.getRecords(searchRequest)).thenReturn(list);
ActionForward forward = action.search(mapping, form, request, response);
}
}
source to share