控制器使用request.getParameter转发,代码如下
public class ComputingController extends HttpServlet {
public ComputingController() {
super();
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String reDirect = request.getParameter("redirect");
RequestDispatcher rd = null;
if ( "update".equals( reDirect ) ) {
UpdateData updateData = new UpdateData();
String updateResult = updateData.doUpdateData();
request.setAttribute( "updateResult", updateResult );
rd = request.getRequestDispatcher("WEB-INF/jsp/computing/success.jsp");
rd.forward(request, response);
}
else {
rd = request.getRequestDispatcher("WEB-INF/jsp/computing/error.jsp");
rd.forward(request, response);
}
}
}
我用Junit和Mockito来测试前锋。
但当我执行测试时(如下),它将在控制器中执行updateData.doUpdateData()。
我如何使用Mockito,让它不执行updateData.doUpdateData(),而是转发?
public class ComputingControllerTest {
@Mock
HttpServletRequest request;
@Mock
HttpServletResponse response;
@Mock
RequestDispatcher rd;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
public void doGet_testForward() throws Exception {
String reDirect = "update";
when(request.getParameter("redirect")).thenReturn( reDirect );
when(request.getRequestDispatcher("WEB-INF/jsp/computing/success.jsp")).thenReturn(rd);
new ComputingController().doGet(request, response);
verify(rd).forward(request, response);
}
}
您的问题是。。。
UpdateData updateData = new UpdateData();
String updateResult = updateData.doUpdateData();
request.setAttribute( "updateResult", updateResult );
你真的不能完全跳过它,只修改你的测试你不会走得太远。因此,您需要的是在其中注入另一个UpdateData()的方法(然后可以对其进行模拟)。例如,一种可能是工厂模式。。。
private UpdateDataFactory factory;
public ComputingController(UpdateDataFactory factory) {
super();
this.factory = factory;
}
public ComputingController() {
super(new DefaultUpdataDataFactory()); // simply creates a new UpdateData();
this.factory = factory;
}
现在你可以写了。。。
UpdateData updateData = this.factory.createUpdataData();
在你的测试中,你可以模拟工厂并插入…
@Mock
private UpdateDataFactory factory;
@Mock
private UpdateData data;
...
when(factory.createUpdataData()).thenReturn (data);
new ComputingController(factory).doGet(request, response);
现在对doUpdataData()的调用将为零,因为它只进入mock,但您可以验证它
哦,你可以通过@InjectMocks自动创建ComputingController(以及注入mock)。。。
@InjectMocks
private ComputingController controller;
如果不修改ComputingController
类的现有源代码,就不可能实现这一点。
如果你愿意修改ComputingController
,下面是你可以做的模拟调用-updateData.doUpdateData()
,
- 在
ComputingController
中创建一个具有默认或protected
级别可访问性的方法getUpdateData()
(private
将不起作用,不建议使用public
)
UpdateData getUpdateData() {return new UpdateData();}
- 用
ComputingController
中的getUpdateData()
替换new UpdateData();
行 - 在
public class ComputingControllerTest
中创建一个非公共类ComputingControllerTestable
class ComputingControllerTestable extends ComputingController {
private UpdateData updateData;
@Override protected void getUpdateData(){return updateData;}
protected void setUpdateData(UpdateData updateData){this.updateData=updateData;}
}
-
现在,在测试类中,将测试中的类类型替换为
ComputingControllerTestable
,而不是ComputingController
-
在
ComputingControllerTest
中,声明一个模拟字段@Mock private UpdateData updateData;
-
现在,在测试类的
@Before
方法中,为测试类的模拟字段testObj.setUpdateData(updateData);
调用ComputingControllerTestable
的setter方法,其中testObj
是步骤#4中创建的测试下的类对象。
我假设被测试的类和测试类在同一个包中。
简单的方法(避免以上6个步骤)是在ComputingController
类中将UpdateData
对象声明为依赖项(实例字段),而不是每次在doGet
方法中创建一个新的UpdateData
,并在ComputingControllerTest
中模拟该依赖项
希望它能有所帮助!!