Susie
Susie

Reputation: 5158

Can you mock a non static method that calls a static method using Mockito?

I understand you can't mock static methods using mockito. But the method I am trying to mock is not static but it has a call to static methods in it. So can I mock this method?

I get exception when I run the test. Is the call to the static method the reason for this exception?

The Class to be tested:

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));**
        }
    }

Mocked 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 I run the test. Please keep in mind that I have changed the names of the classes for simplicity. enter image description here

Upvotes: 3

Views: 2920

Answers (1)

kan
kan

Reputation: 28981

The problem is that your search method cannot use the service mock, because it creates its own instance by MyService service = new MyClass();. So you must refactor the MyAction class to allow MyService injection and inject a mock in it. Or use more heavy weapon - PowerMock.

Easiest and safest Refactoring

Use in your IDE "extract method" refactoring to extract construction "new MyClass()". So it will become:

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 your unit test you could inject a 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);        
    }

}

Upvotes: 6

Related Questions