Java 你能用Mockito模拟一个调用静态方法的非静态方法吗?

Java 你能用Mockito模拟一个调用静态方法的非静态方法吗?,java,unit-testing,mocking,tdd,mockito,Java,Unit Testing,Mocking,Tdd,Mockito,我知道你不能用mockito模拟静态方法。但是我试图模拟的方法不是静态的,但是它在其中调用了静态方法。那么我可以嘲笑这个方法吗 我在运行测试时遇到异常。对静态方法的调用是否是此异常的原因 要测试的类: public class MyAction{ public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse re

我知道你不能用mockito模拟静态方法。但是我试图模拟的方法不是静态的,但是它在其中调用了静态方法。那么我可以嘲笑这个方法吗

我在运行测试时遇到异常。对静态方法的调用是否是此异常的原因

要测试的类:

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));**
        }
    }
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;
    }
}
public class DAOFactory{
        private static DAOFactory instance = new DAOFactory();

         public static DAOFactory getInstance() {------> The static method
            return instance;
        }       
    }
@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);        
}
模拟类和方法:

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));**
        }
    }
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;
    }
}
public class DAOFactory{
        private static DAOFactory instance = new DAOFactory();

         public static DAOFactory getInstance() {------> The static method
            return instance;
        }       
    }
@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);        
}
使用静态方法初始化:

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));**
        }
    }
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;
    }
}
public class DAOFactory{
        private static DAOFactory instance = new DAOFactory();

         public static DAOFactory getInstance() {------> The static method
            return instance;
        }       
    }
@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);        
}
我的测试:

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));**
        }
    }
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;
    }
}
public class DAOFactory{
        private static DAOFactory instance = new DAOFactory();

         public static DAOFactory getInstance() {------> The static method
            return instance;
        }       
    }
@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);        
}
@测试
public void testSearch()引发异常{
MyService=mock(MyService.class);
MyAction动作=新的MyAction();
列表=新的ArrayList();
when(service.getRecords(searchRequest)),然后return(list);
ActionForward=action.search(映射、表单、请求、响应);
}
这是我运行测试时的堆栈跟踪。请记住,为了简单起见,我已经更改了类的名称。

问题在于,您的
搜索
方法无法使用服务模拟,因为它通过
MyService service=new MyClass()创建自己的实例。因此,您必须重构
MyAction
类,以允许
MyService
注入并在其中注入模拟。或者使用更重的武器-PowerMock

最简单、最安全的重构

在IDE“extract method”重构中使用以提取构造“new MyClass()”。因此,它将成为:

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

    }
然后在单元测试中,您可以通过创建内部子类来注入模拟:

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

}
公共类MyActionTest{
私有MyService=mock(MyService.class);
private MyAction=new MyAction(){
@凌驾
MyService getMyService(){return service;}
};
@试验
public void testSearch()引发异常{
列表=新的ArrayList();
when(service.getRecords(searchRequest)),然后return(list);
ActionForward=action.search(映射、表单、请求、响应);
}
}

Doh-我一直在寻找更复杂的情况,完全忽略了服务模拟未使用的事实…@JonSkeet He。。。他是一名学生……:)尽管重构目前不是一个选项,因为我被要求为一些遗留代码编写测试,但我如何重构它以便注入模拟代码?Thanks@javaStudent我已将其中一种方法添加到我的answer@javaStudent一个被模拟的方法根本不会被执行,所以它对什么都不重要。