Test a void method that redirect foward

放肆的年华 提交于 2020-01-02 08:03:07

问题


How can I test a void method that redirects me with RequestDispatcher?

What I made until now.

public void testAuthAction_userNull() {
    HttpServletRequest requestMock = createMock(HttpServletRequest.class);
    HttpServletResponse responseMock = createMock(HttpServletResponse.class);
    expect(requestMock.getSession().getAttribute("user")).andReturn(null);
    replay(requestMock);

    AuthAction action = new AuthAction();
    RequestDispatcher rd = requestMock.getRequestDispatcher("/User/login.jsp");
}

the method I want to the test is.

public void execute(HttpServletRequest request, HttpServletResponse response) {
    User user = (User) request.getSession().getAttribute("User");
    try {
        if(user == null) {
            RequestDispatcher rd = request.getRequestDispatcher("/User/login.jsp");
            if(rd != null)
                rd.foward(request, response);
        } else {/* */}
    }
    catch(Exception e){/* */}
}

I'm using JUnit and EasyMock.


回答1:


You need to create a mock of RequestDispatcher expecting to be forwarded, and return it from your mock:

RequestDispatcher dispatcherMock = createMock(RequestDispatcher.class);
expect(requestMock.getRequestDispatcher("/User/login.jsp"))
    .andReturn(dispatcherMock);
// Expect to be forwarded.
dispatcherMock.forward(requestMock, responseMock);
EasyMock.expectLastCall().once();
replay(dispatcherMock);
replay(requestMock);

// Run your test on whatever instance has `execute`:
someInstance.execute(requestMock, responseMock);



回答2:


I will provide a long answer that should be helpful I think.

So, the tested method is this.

public void execute(HttpServletRequest request, HttpServletResponse response) {
    User user = (User) request.getSession().getAttribute("User");
    try {
        if(user == null) {
            RequestDispatcher rd = request.getRequestDispatcher("/User/login.jsp");
            if(rd != null)
                rd.forward(request, response);
        } else {/* */}
    }
    catch(Exception e){/* */}
}

A working test method would be this:

@Test
public void testAuthAction_userNull() {
    HttpServletRequest requestMock = mock(HttpServletRequest.class);
    HttpServletResponse responseMock = mock(HttpServletResponse.class);
    HttpSession sessionMock = mock(HttpSession.class);

    expect(requestMock.getSession()).andReturn(sessionMock);
    expect(sessionMock.getAttribute("User")).andReturn(null);
    expect(requestMock.getRequestDispatcher("/User/login.jsp")).andReturn(null);

    replay(requestMock, sessionMock);

    execute(requestMock, responseMock);

    verify(requestMock, sessionMock);
}

I am using mock() instead of createMock(). It's the same but nicer and shorter.

It returns a null dispatcher because nothing more is needed. I've added a verify() to make sure everything was called as expected.

Then, if you want to make sure the forward is called as well, you also need a mock for the RequestDispatcher.

@Test
public void testAuthAction_userNull() throws Exception {
    HttpServletRequest requestMock = mock(HttpServletRequest.class);
    HttpServletResponse responseMock = mock(HttpServletResponse.class);
    HttpSession sessionMock = mock(HttpSession.class);
    RequestDispatcher rdMock = mock(RequestDispatcher.class);

    expect(requestMock.getSession()).andReturn(sessionMock);
    expect(sessionMock.getAttribute("User")).andReturn(null);
    expect(requestMock.getRequestDispatcher("/User/login.jsp")).andReturn(rdMock);

    rdMock.forward(requestMock, responseMock);

    replay(requestMock, sessionMock, rdMock);

    execute(requestMock, responseMock);

    verify(requestMock, sessionMock, rdMock);
}

The verify() will make sure forward() is called. You do not need an expectLastCall(). It is implicit.

Then to simplify, I would actually do this:

public class MyTest extends EasyMockSupport {
    @Test
    public void testAuthAction_userNull() throws Exception {
        HttpServletRequest requestMock = mock(HttpServletRequest.class);
        HttpServletResponse responseMock = mock(HttpServletResponse.class);
        HttpSession sessionMock = mock(HttpSession.class);
        RequestDispatcher rdMock = mock(RequestDispatcher.class);

        expect(requestMock.getSession()).andReturn(sessionMock);
        expect(sessionMock.getAttribute("User")).andReturn(null);
        expect(requestMock.getRequestDispatcher("/User/login.jsp")).andReturn(rdMock);

        rdMock.forward(requestMock, responseMock);

        replayAll();

        execute(requestMock, responseMock);

        verifyAll();
    }
}

The EasyMockSupport class makes the code simpler.

And to be honest, in this case, when using Spring, I would use spring-test.

@Test
public void testAuthAction_userNull() throws Exception {
    MockHttpServletRequest request = new MockHttpServletRequest();
    MockHttpServletResponse response = new MockHttpServletResponse();

    execute(request, response);

    assertThat(response.getForwardedUrl()).isEqualTo("/User/login.jsp");
}

It does the exact same thing but as you can see it is much shorter because the session and request dispatcher are created under the hood to behave like you would expect.



来源:https://stackoverflow.com/questions/50106350/test-a-void-method-that-redirect-foward

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!