我怎样才能使用Mockito来测试前锋?

时间:2015-12-31 06:50:48

标签: junit controller mockito forward

Controller使用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);

    }
}

2 个答案:

答案 0 :(得分:2)

你的问题是这个......

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()的调用将一无所获,因为它只会进入模拟,但你可以验证它

哦,你可以通过@InjectMocks自动创建ComputingController(并注入模拟)......

 @InjectMocks
 private ComputingController controller;

答案 1 :(得分:2)

如果不修改ComputingController类的现有源代码,就无法实现这一目标。

如果您愿意修改ComputingController,则可以使用以下内容模拟通话 - updateData.doUpdateData()

  1. getUpdateData()中使用默认或ComputingController级别辅助功能创建方法protectedprivate不起作用且不建议使用public),
  2. UpdateData getUpdateData() {return new UpdateData();}

    1. 将行new UpdateData();替换为getUpdateData()
    2. 中的ComputingController
    3. ComputingControllerTestable
    4. 中创建非公开课public class ComputingControllerTest

      class ComputingControllerTestable extends ComputingController { private UpdateData updateData; @Override protected void getUpdateData(){return updateData;} protected void setUpdateData(UpdateData updateData){this.updateData=updateData;} }

      1. 现在,在您的测试类中,将测试中类类型替换为ComputingControllerTestable而不是ComputingController

      2. ComputingControllerTest中,声明一个模拟字段,@Mock private UpdateData updateData;

      3. 现在,在您的@Before测试类方法中,为测试类的模拟字段ComputingControllerTestable调用testObj.setUpdateData(updateData);的setter方法,其中testObj在第4步中创建的测试阶段对象。

      4. 我假设您的测试类和测试类在同一个包中。

        简单方法(避免上述所有6个步骤)是将UpdateData对象声明为ComputingController类中的依赖项(实例字段),而不是每次在UpdateData内创建新doGet {1}}方法并在ComputingControllerTest

        中模拟依赖项

        希望它有所帮助!!