如何对JSP文件进行单元测试?


12

我正在开发Java 6 EE应用程序,并且正在用另一版本的jsp代码测试我的jsp代码,该版本具有测试版本的函数调用和原始版本中使用的代码,但它看起来松散且不切实际。有没有一种好的方法来完成这种测试?


2
您需要从测试中了解什么?

Answers:


15

如果您尚未阅读有关MVC(模型视图控制器)的信息,请阅读。您不应该在JSP中包含代码,只需显示即可。将代码放入JSP是1900年代。

严重的是,如果JSP中没有代码,则您不是在测试JSP。您正在测试操作/流程。然后,您可以使用HttpUnitSelenium。最大的区别在于Selenium是从真实的浏览器进行测试。


13

我认为没有测试JSP的好方法,主要是因为JSP是在单元测试成为开发重点之前开发的。

罗伯特·马丁(Robert Martin)几年前写了一篇文章,内容涉及黑客JSP编译器,以便您可以直接进行基于非容器的单元测试。他的想法很好,但是在下一个TomCat主要版本中就被打破了。发生了太多的魔术。

我不同意“只要不添加代码,您就不需要测试它”的想法。显然,您不应该将代码放入JSP中。但是,尽管如此,复杂的UI仍将经常具有可进行有益的单元测试的显示逻辑。

考虑以下示例:

<c:choose>
  <c:when test="${mydto.showAdminMenu}">
   The admin menu....
  </c:when>
  <c:otherwise>
    Something completely different
  </c:otherwise>
</c:choose>

这段代码已经被充分考虑:决定我们是否显示管理菜单的逻辑不在视图中。尽管如此,如果有一种简单的方法来对JSP进行单元测试,那么我们可以编写一个测试来表明我们想要的行为实际上已经出现,并且可以保护我们免受页面更改的影响,该页面在需要时意外地使管理菜单可见不是。


4

存在一个程序(供您使用的任何应用程序服务器使用),该程序可将.jsp文件编译为.java文件。例如,sun / oracle版本jspc

一旦有了由.jsp转换生成的.java(您甚至可以考虑在构建过程中使用它-预编译jsp以提高性能),然后可以对其进行测试通过模拟请求并验证响应是否符合您的期望。

(编辑示例:)

关键方法是_jspService(HttpServletRequest, HttpServletResponse)方法。

一个简单的hello world jsp:

<html>
    <head>
        <title>Hello world</title>
    </head>
    <body>
        <h1>Hello world</h1>
        Today is: <%= new java.util.Date().toString() %>
    </body>
</html>

(test.jsp位于名为“ webapp”的目录中,并且也位于“ out”目录中)。使用命令编译时,jspc -v -d out -compile -uriroot webapp/ test.jsp会将名为的文件放入out目录中test_jsp.java。该文件包含在其中(以及相当多的其他配置设置):

  public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException {

    PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    Object page = this;
    JspWriter _jspx_out = null;
    PageContext _jspx_page_context = null;

    try {
      response.setContentType("text/html");
      pageContext = _jspxFactory.getPageContext(this, request, response,
                null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("<html>\n\t<head>\n\t\t<title>Hello world</title>\n\t</head>\n\t<body>\n\t
\t<h1>Hello world</h1>\n\t\tToday is: ");
      out.print( new java.util.Date().toString() );
      out.write("\n\t</body>\n</html>\n\n");
    } catch (Throwable t) {
      if (!(t instanceof SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try { out.clearBuffer(); } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

在这一点上,检查以确保JspWriter是用write或print调用的,并且调用的内容就是您所期望的。

综上所述,在理想的世界中,jsp内不应包含任何逻辑-这种逻辑可以在控制器中或在使用其他技术测试过的taglib中。


1
JSP中将要测试/模拟的内容是什么?在请求/会话中设置数据,然后检查显示?还是如果没有遵循良好实践并且JSP中存在实际逻辑,这是吗?
Jeanne Boyarsky 2012年

@JeanneBoyarsky更新了示例jsp和代码。我认为尝试使用传统的junit进行测试(这是另一个测试领域)不是一个好习惯。取决于工具集,模拟的深度可能很尴尬(例如,将JspWriter子类化,以便可以轻松测试发送给它的内容)。

3

您也可以考虑使用HTTP单元测试框架,例如HTTPUnit | http://httpunit.sourceforge.net/

另一个重要的点是将您的应用程序关注点分开。

例如,使用TDD(http://en.wikipedia.org/wiki/Test-driven_development)之类的技术,您将设计可测试性的类型。

JSP中使用的类型将在特定的单元测试中进行测试。如果不可能,则应模拟用户->浏览器交互(同样,HTTPUnit或类似工具)。


2
  • 尝试外部化Servlet的功能代码,以使用实际的单元测试在Servlet上下文之外对其进行测试
  • 使用以下工具测试servlet端点:
    • HTTPUnit
    • HtmlUnit
    • 仙人掌
    • JspTest
    • ...
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.