JUint学习笔记12---对servlet和filter进行单元测试1

来源:互联网 发布:android算法面试题 编辑:程序博客网 时间:2024/06/07 06:15

第三部分  testing components

                       从JUnit学习笔记1到11都是讲基本的测试尝试,懂得前面的知识,就可以开始Junit in action的最后一程了---测试组件。

       第三部分让你把在第一第二部分学到的测试知识实践于J2EE组件。我们将重点学习为各种J2EE组件编写单元测试,并能学习如何用Ant、Maven和Eclipse这些工具进行测试。

     第九章 对servlet和filter进行单元测试   Unit-testing servlets and filters

       本章内容

  • 示范测试驱动开发(TDD)方法
  • 用Cactus和mock objects编写servlet和filter的单元测试程序
  • 用Maven运行Cactus测试程序
  • 选择何时用Cactus,何时用mock objects

     介绍管理应用程序

   这个示例管理就是目的是要让管理者对关系数据库进行查询。下图就是典型的web应用框架:

(看不到图片的朋友请点这里)

image

           应用程序首先接受用户包含执行SQL查询的HTTP请求。请求被一个安全filter捕获,该安全filter是用来检查SQL查询是否是一个SELECT查询。如果不是,用户将被定向到一个错误的页面,如果查询是一个SELECT语句,那么就将调用AdminServlet。该servlet执行请求的数据库查询,并将结果传送到JSP显示页面。

用Cactus编写servlet测试

       在这部分的内容中,我们重点是进行AdminServlet部分执行单元测试。在写代码之前就开始写测试程序叫驱动测试开发或测试先行策略。

       先来分析一下AdminServlet的需求,该servlet从Http请求中提取包括将要执行命令的需用参数。然后它将使用提取的命令来获取数据。最后将控制权交给JSP页面来显示穿过来的数据。我们把对应于这些行为的方法分别称为getCommand、executeCommand和callView。

       设计第一个测试

         下面的代码给出了对getCommand方法的测试。

package junitbook.servlets;import java.util.ArrayList;import java.util.Collection;import java.util.List;import javax.servlet.ServletException;import org.apache.cactus.ServletTestCase;import org.apache.cactus.WebRequest;import org.apache.commons.beanutils.BasicDynaClass;import org.apache.commons.beanutils.DynaBean;import org.apache.commons.beanutils.DynaProperty;public class TestAdminServlet extends ServletTestCase{    public void beginGetCommandOk(WebRequest request)    ;测试有效的情况    {                                                    ;定义了command        request.addParameter("command", "SELECT...");    ;作为Http的参数    }                                                    ;                                                         ;    public void testGetCommandOk() throws Exception      ;    {                                                    ;        AdminServlet servlet = new AdminServlet();       ;        String command = servlet.getCommand(request);    ;                                                         ;        assertEquals("SELECT...", command);              ;    }        public void testGetCommandNotDefined()      ;测试无效的情况,没有定义命令参数    {        AdminServlet servlet = new AdminServlet();        try         {            servlet.getCommand(request);            fail("Command should not have existed");        }        catch (ServletException expected)        {            assertTrue(true);        }            }}

能让TestAdminServlet编译通过的最简单的代码

package junitbook.servlets;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;public class AdminServlet extends HttpServlet{       public String getCommand(HttpServletRequest request)        throws ServletException    {        return null;    }}

在你继续其它测试和实现满足测试的最小应用之前,设法运行Cactus测试。虽然是失败的,但是你至少知道为什么会失败。 然后,当你实现测试中的代码时,测试将会成功!

   -----------------------------------------------------------------------------------------------    
   -JUnit最佳实践  记得检验测试在应当失败的时候失败---------------------------------------------------

使用Maven来运行Cactus测试

     在前面我们已经学习了使用Cactus/Jetty集成,从一个IDE中来进行Cactus测试。这次,我们将学会使用Maven Cactus插件在Tomcat中进行测试。Tomcat是众所周知的servlet/JSP引擎。Maven Cactus插件是运行Cactus测试最容易的方法之一。所有的事物对于使用者来说都是自动和透明的:你的应用文件war文件的“cactus”化、启动你的容器、配置“cactus”化的war,执行Cactus测试,及停止你的容器。(“cactus化”就是自动附加Cactus jars,并且把Cactus需要的入口附加在你的web.xml文件中)。

    默认情况下,Maven Cactus插件在src/testcactus目录下查找Cactus测试程序。我们也需要将所有的元数据和资源文件放在src/webapp目录下。管理应用程序的web.xml文件如下:

1.0" encoding="ISO-8859-1"?>-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"    "http://java.sun.com/dtd/web-app_2_3.dtd">      AdminServlet    <servlet-class>junitbook.servlets.AdminServletclass>        AdminServlet    /AdminServlet  

   要用Maven运行Cactus测试,我们还要提供一个有效的project.xml文件,代码如下,关于细节,在前面的笔记中有描述

1.0" encoding="ISO-8859-1"?>  3  junitbook-servlets  JUnit in Action - Unit-testing servlets and filters  1.0      Manning Publications Co.    http://www.manning.com/    http://www.manning.com/front/dance.gif    2002-2003  <package>junitbook.servletspackage>  /images/jia.jpg      Chapter 9 shows how to unit test Servlets annd Filters using     both the Mock Object approach and the in-container approach.     It highlights how they complement each other and give     strategies on when to use them.         Chapter 9 of JUnit in Action: Unit-testing servlets and filters    http://sourceforge.net/projects/junitbook/            Vincent Massol      vmassol      vmassol@users.sourceforge.net      Pivolis              Java Developer                        commons-beanutils      commons-beanutils      1.6.1              true                    servletapi      servletapi      2.3              easymock      easymock      1.0              mockobjects      mockobjects-core      0.09            src/java    src/test                  **/Test*.java                    **/Test*All.java                  maven-cactus-plugin  
  1. 首先,定义你要运行时需要的jar文件。你不需要包含Cactus相关jar,因为Maven Cactus插件自动包含这些jar。
  2. Maven Cactus插件使用war文件。元素告诉Maven在生产的成品war中包括Commons BeanUtils jars。成品war已被Maven Cactus插件cactus化。注意因为你将会在你的servlet中使用Commons BeanUtils jars,所以必须包含对BeanUtils的依赖关系。
  3. 包含/排除纯粹的JUnit测试以匹配你想运行的测试。
  4. 列出生成的报告。

在运行Cactus插件之前,你要通告Cactus插件,Tomcat被安装在你机器哪个位置,这样才能在能在容器中运行Cactus测试。Cactus插件需要你在你的project.properties文件中增加下面的这一行:

           cactus.home.tomcat4x =C:/Apps/jakarta-tomcat-4.1.24

完成Cactus servlet测试

 使得测试通过的getCommand实现

package junitbook.servlets;import java.util.Collection;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class AdminServlet extends HttpServlet{    public static final String COMMAND_PARAM = "command";         public String getCommand(HttpServletRequest request)        throws ServletException    {        String command = request.getParameter(COMMAND_PARAM);        if (command == null)        {            throw new ServletException("Missing parameter ["                + COMMAND_PARAM + "]");        }        return command;    }    public void callView(HttpServletRequest request)    {    }}
测试callView方法
  在TestAdminServlet中添加如下代码:
 private Collection createCommandResult() throws Exception    {        List results = new ArrayList();                DynaProperty[] props = new DynaProperty[] {            new DynaProperty("id", String.class),            new DynaProperty("responsetime", Long.class)        };        BasicDynaClass dynaClass = new BasicDynaClass("requesttime",             null, props);        DynaBean request1 = dynaClass.newInstance();        request1.set("id", "12345");        request1.set("responsetime", new Long(500));        results.add(request1);        DynaBean request2 = dynaClass.newInstance();        request1.set("id", "56789");        request1.set("responsetime", new Long(430));        results.add(request2);                return results;    }             public void testCallView() throws Exception    {        AdminServlet servlet = new AdminServlet();               // Set the result of the exection of the command in the        // HTTP request so that the JSP page can get the data to        // display                 request.setAttribute("result", createCommandResult());        servlet.callView(request);    }    public void beginDoGet(WebRequest request)    {        request.addParameter("command", "SELECT...");    }
使得测试通过的callView方法
         放到AdminServlet.java中
  public void callView(HttpServletRequest request)    {    }    public Collection executeCommand(String command)         throws Exception    {        throw new RuntimeException("not implemented");    }
测试doGet方法 
doGet的单元测试
 public void beginDoGet(WebRequest request)    {        request.addParameter("command", "SELECT...");    }    public void testDoGet() throws Exception    {        AdminServlet servlet = new AdminServlet()        {            public Collection executeCommand(String command)                 throws Exception            {                return createCommandResult();            }        };                      servlet.doGet(request, response);        // Verify that the result of executing the command has been        // stored in the HTTP request as an attribute that will be        // passed to the JSP page.        Collection results =             (Collection) request.getAttribute("result");                assertNotNull("Failed to get execution results from the "            + "request", results);                       assertEquals(2, results.size());    }

使得测试通过的doGet方法

 public void doGet(HttpServletRequest request,        HttpServletResponse response) throws ServletException    {        try         {            Collection results =                 executeCommand(getCommand(request));            request.setAttribute("result", results);                }        catch (Exception e)        {            throw new ServletException(                "Failed to execute command", e);        }    }

有两点需要注意,首先,对callView的调用在doGet中没有出现;测试也没有要求。其次executeCommand被调用,将抛出RuntimeException异常,当然你也可以返回null,但是抛出异常是个比较好的做法,如果方法被错误的调用,你也就不会感到任何的惊奇。 

                                                                                                                                 笔记十二是描述使用mock objects测试servlet