如何创建ServletContext的mock属性?

时间:2017-06-19 19:50:56

标签: java unit-testing servlets mocking mockito

我有Servlet在数据库中添加用户。 Servlet使用模块实例来处理数据库的别名DBJoint。 Servlet从DBJoint获取ServletContext的实例。

@WebListener
public class ContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        final ServletContext servletContext =
                servletContextEvent.getServletContext();

        final DBJoint joint = new DBJointHandler(
                "database_scripts",
                "authentication_database");

        servletContext.setAttribute("db", joint);
    }
}

当我需要使用数据库时,在每个Servlet中,我调用ServletContext并按键DBJoint获取"db"

public class AddUserServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        req.setCharacterEncoding("UTF8");

        try {

            final boolean success = addUserInDatabase(req);

            if (success) req.setAttribute("serverAnswer", EDIT_SUCCESS.get());
            else req.setAttribute("serverAnswer", ERR_UNIQUE_L_P.get());

            req.getRequestDispatcher(ANSWER.get())
                    .forward(req, resp);

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * Addition user in database.
     *
     * @return true if addition success, else false.
     */
    private boolean addUserInDatabase(final HttpServletRequest req)
            throws SQLException {

        final User user = getUserFromRequest(req);
        return getDatabaseExecutor().addUserAndGetSuccess(user);
    }

    /**
     * Extracts user's data from HttpServletRequest.
     *
     * @return user from request.
     */
    private User getUserFromRequest(final HttpServletRequest req) {
        return new User(
                req.getParameter("name"),
                req.getParameter("login"),
                req.getParameter("password"),
                req.getParameter("email"),
                req.getParameter("role")
        );
    }

    /**
     * Get executor database requests.
     */
    private ScriptExecutor getDatabaseExecutor() throws SQLException {
        final DBJoint db = (DBJoint) getServletContext().getAttribute("db");
        return db.getDBScriptExecutor();
    }
}

我需要测试我的Servlet,并使用模拟对象代替原始对象:

在这个测试中,我尝试验证doPost在数据库脚本的执行器中调用addUser(User u)的主体。但是要获得NPE。

@Test
public void whenUserAddThenAddUserCall() throws ServletException, IOException, SQLException {

    final AddUserServlet servlet = new AddUserServlet();

    //mock http.
    HttpServletRequest request = mock(HttpServletRequest.class);
    HttpServletResponse response = mock(HttpServletResponse.class);

    User user = new User("name", "login", "password", "email");

    //mock database.
    ScriptExecutor executor = mock(ScriptExecutor.class);

    DBJoint joint = mock(DBJointHandler.class);
    when(joint.getDBScriptExecutor()).thenReturn(executor);


    final ServletContext context = request.getServletContext();
    //In this place I get NPE but why?
    context.setAttribute("db", joint);

    servlet.doPost(request, response);

    verify(executor).addUser(user);
}

为什么我有NullPointerException?怎么测试这门课?谢谢!

2 个答案:

答案 0 :(得分:0)

您正在调用request.getServletContext()对象上的request

模拟对象不提供真正的方法实现。而不是真正的getServletContext()实现,该方法的存根版本被称为返回null。

应该告诉模拟在调用方法时需要返回什么,你需要像对DBJoinHandler mock一样定义行为。

要解决NPE,请执行以下操作:

when(request.getServletContext()).thenReturn(context);

其中context可以是ServletContext模拟。

答案 1 :(得分:0)

您还需要包含这些

ServletContext context = mock(ServletContext .class)
when(request.getServletContext()).thenReturn(context );