Struts 测试

 

StrutsTestCase介绍

    StrutsTestCase工程提供了一种在JUnit框架下测试struts action的灵活、便利的方法。你可以通过设置请求参数,检查在Action被调用后的输出请求或Session状态这种方式对Struts Action做白盒测试。StrutsTestCase 提供了用框架模拟web容器的模拟测试方法也提供了真实的web容器(比如:Tomcat)下的测试方法。所有的StrutsTestCase单元测试类都源于模拟测试的 MockStrutsTestCase或容器内测试的CactusStrutsTestCase。
    下面的例子就是使用mock测试,因为它需要更少的启动和更快的运行。
要使用StrutsTestCase请在下列地址下载最新的发行包
[url]http://sourceforge.net/project/showfiles.php?group_id=39190[/url]

      下面就开始我们的action测试之旅。首先先让我们了解一下要实现的程序的功能:在search.jsp中输入班级编号以列表形式在result.jsp页面中显示相关班级学员信息。在result.jsp中点击学员姓名在info.jsp中显示该学生的详细信息。 下面的请求URL将会显示调用SearchAction类:search.do?method=search
      具体步骤如下:
      步骤1:在eclipse中放入strutstests-2.1.3.jar,junit.jar、commons-collections.jar
      步骤2:编写测试类
构造一个名为SearchActionTest的类并继承MockStrutsTestCase。在该类中添
加测试方法testSearchSuccess


   1. import servletunit.struts.MockStrutsTestCase;        
   2.        
   3. public class SearchActionTest extends MockStrutsTestCase        
   4. {        
   5.    public void testSearchSuccess()        
   6.    {        
   7.       setRequestPathInfo("/search.do");          //1行        
   8.       addRequestParameter("method", "search");  //2行        
   9.       actionPerform();                          //3行        
  10.   }        
  11. }      


       代码解释:
       1行:设置请求SearchAction类的请求路径
       2行:在请求路径后加上一个请求参数
                1行与2行就构成了/search.do?method=search
       3行:调用actionPerform()来执行action类
       注:以上代码就是对一个测试方法的初始化。可以根据需要自行修改

       步骤5:根据struts-config.xml文件完善testSearch方法。先验证可以按照班级名称查询出所需要的数据,主要做以下事情:
       a)   初始化提交数据
       b)   验证request中"result"属性是否有值
       c)   是否返回result.jsp页面   
       代码如下:


   1. public class SearchActionTest extends MockStrutsTestCase        
   2. {        
   3.     public void testSearchSuccess()        
   4.     {        
   5.         setRequestPathInfo("/search.do");        
   6.         addRequestParameter("method", "search");        
   7.              
   8.         addRequestParameter("clazzName","gs2t11");      //1行        
   9.         actionPerform();        
  10.              
  11.         assertNotNull(request.getAttribute("result"));  //2行        
  12.         verifyForward("success");                       //3行        
  13.     }        
  14. }      

       代码解释:
       1行:添加提交数据,该数据就相当与从search.jsp提交的数据
       2行:查询成功后,将结果放入request中,所以判断result中的"result"属性是否
                 有值来断定是否将结果成功放入request对象中。
       3行:验证查询成功后是否会返回success.jsp页面
       运行junit,如果出现以下错误(具体如下图):(请参考附件吧。这里所有的图都省略……)
       那么请在src下建立一个名WEB-INF的目录,将WebRoot下的WEB-INF中的web.xml文件与struts-config.xml文件拷贝过去即可。如图:


       步骤6:在SearchAction中用最简单的代码先去实现步骤5中的功能
       代码如下:           


   1. public class SearchAction extends DispatchAction   
   2. {   
   3.     private SearchHandler sh;   
   4.   
   5.     public ActionForward search(ActionMapping mapping,ActionForm   
   6.               form, HttpServletRequest request, HttpServletResponse response)   
   7.     {   
   8.         SearchFormsearchForm = (SearchForm) form;   
   9.         //获取表单中输入的班级   
  10.         String className = searchForm.getClazzName();   
  11.            
  12.         //查询该班级的信息   
  13.         sh = new SearchHandler();   
  14.         List list=sh.searchByClassName(className);   
  15.            
  16.         if(list!=null)   
  17.         {   
  18.             //将班级信息保存至request中,并返回result.jsp   
  19.             request.setAttribute("result",list);   
  20.             return mapping.findForward("success");   
  21.         }   
  22.         else  
  23.             return null;   
  24.     }   
  25. }  

           注释比较详细,就不再多解释了
        运行测试类结果如下(成功部分编写完毕)

        步骤7:编写不能成功取出数据的测试。在SearchActionTest类中添加一个名为testSearchFail的方法
       代码如下:      


   1. public void testSearchFail()   
   2. {   
   3.     setRequestPathInfo("/search.do");   
   4.     addRequestParameter("method", "search");   
   5.            
   6.     addRequestParameter("clazzName","gs2txx");       //1行   
   7.     actionPerform();   
   8.            
   9.     verifyActionMessages(new String[] {"no.stuclass.found"});//2行   
  10.     verifyForward("error");                            //3行   
  11.            
  12.     verifyForwardPath("/error.jsp");                              //4行   
  13. }  

       代码解释:
       1行:输入一个不存在的班级
       2行:验证向ActionMessages中放入的消息文本
       3行:验证返回地址
       4行:验证页面地址是否与转向的error对应

      步骤8:更改SearchAction类,实现步骤7的功能
      代码如下:(粗体为增加部分)


   1. public class SearchAction extends DispatchAction   
   2. {   
   3.     private SearchHandler sh;   
   4.   
   5.     public ActionForward search(ActionMapping mapping,ActionForm   
   6.              form, HttpServletRequest request, HttpServletResponse response)   
   7.     {   
   8.         SearchFormsearchForm = (SearchForm) form;   
   9.         //获取表单中输入的班级   
  10.         String className = searchForm.getClazzName();   
  11.            
  12.         //查询该班级的信息   
  13.         sh = new SearchHandler();   
  14.         List list=sh.searchByClassName(className);   
  15.            
  16.         if(list!=null)   
  17.         {   
  18.             //将班级信息保存至request中,并返回result.jsp   
  19.             request.setAttribute("result",list);   
  20.             return mapping.findForward("success");   
  21.         }   
  22.         else  
  23.         {   
  24.              //构造一个ActionMessage保存一条消息   
  25.              ActionMessages messages=new ActionMessages();   
  26.              messages.add(Globals.MESSAGE_KEY, new ActionMess("no.stuclass.found"));
                   saveMessages(request,messages);   
  27.              //返回error.jsp   
  28.              return mapping.findForward("error");   
  29.         }   
  30.     }   
  31. }  


       运行测试类,正确
                   
     经过前面两个功能的测试与运行,两个功能都可以单独测试通过,由于第二个功能是以第一个功能成功查询为前提才能运行,所以再编写一个测试,将两个 action功能整合。这样就可以测试整个功能模块是否正确。在DisplayActioTest中编写一个名为 testSearchAndDisplay()的方法来完成这个测试吧。

       代码如下:


   1. public void testSearchAndDisplay()   
   2. {   
   3.     //先调用SearchAction来取得数据   
   4.     setRequestPathInfo("/search.do");   
   5.     addRequestParameter("method", "search");   
   6.            
   7.     addRequestParameter("clazzName","gs2t11");   
   8.     actionPerform();   
   9.            
  10.     List list=(List) request.getAttribute("result");   
  11.     Student student=(Student) list.get(0);   
  12.            
  13.     //调用DisplayAction类显示在result.jsp中选择的数据   
  14.     setRequestPathInfo("/display.do");   
  15.     addRequestParameter("method","display");   
  16.     addRequestParameter("stuName", student.getStuName());   
  17.            
  18.     actionPerform();   
  19.   
  20.     assertNotNull(request.getAttribute("stu"));   
  21.     verifyForward("info");   
  22. }  


        运行测试类,测试成功

        整个模块到这里全部开发测试完毕,但是还没完,作为测试驱动开发最重要的一环就是重构,这样才能保证你程序的健壮性、可读性、可维护性及优雅性。这里重构主要是针对Action类进行重构,你也可以用同样的方法在编写完测试代码之后对测试代码进行重构。这里主要针对以下几个地方进行重构
        1)   抽取Action类中的变量:

               SearchAction类中:


   1. SearchForm searchForm= (SearchForm) form;     
   2. String className = searchForm.getClazzName();     
   3. sh = new SearchHandler();     
   4. List list=sh.searchByClassName(className);   


               可以用下列代码替换:


   1. sh = new SearchHandler();     
   2. List list=sh.searchByClassName(((SearchForm) form).getClazzName());   


                DisplayAction类中:


   1. DisplayForm displayForm = (DisplayForm) form;     
   2. String name=displayForm.getStuName();     
   3. Student stu=sh.displayByName(name);     
   4. request.setAttribute("stu",stu);   


               可以用下列代码替换:


   1. request.setAttribute("stu",sh.displayByName(((DisplayForm)form).getStuName()));   

        2)  抽取常量:

               SearchAction类中:


   1. request.setAttribute("result",list);      

               可以用下列代码替换


   1. private static final String RESULT = "result";     
   2. request.setAttribute(RESULT,list);   

              SearchAction类中


   1. request.setAttribute("stu",sh.displayByName(((DisplayForm) form).getStuName()));   

              可以用下列代码替换


   1. private static final String STUDENT = "stu";     
   2. request.setAttribute(STUDENT,sh.displayByName(((DisplayForm) form).getStuName()));   

        构造一个名为BaseAction的类,继承DispatchAction类,并在其中初始化一个SearchHandler对象


   1. public class BaseAction extends DispatchAction     
   2. {     
   3.     protected SearchHandler sh=new SearchHandler();     
   4. }   


        SearchAction类与DisplayAction类可改为


   1. public class SearchAction extends BaseAction     
   2. public class DisplayAction extends BaseAction   


        同时要去掉两个类中的SearchHandler属性

        SearchAction类中下列代码可以抽取成方法:


   1. ActionMessages messages=new ActionMessages();     
   2. messages.add(Globals.MESSAGE_KEY, new ActionMessage("no.stuclass.found"));     
   3. saveMessages(request,messages);   


        可以用下列代码替换:


   1. addResultMessage(request,"no.stuclass.found");   
   2.   
   3. private void addResultMessage(HttpServletRequest request,String message)   
   4. {   
   5.      ActionMessages messages=new ActionMessages();   
   6.      messages.add(Globals.MESSAGE_KEY, new ActionMessage("no.stuclass.found"));   
   7.      saveMessages(request,messages);   
   8. }  


       由于在别的Action中也要经常生成ActionMessages对象,所以再将该方法 抽取到BaseAction中。

       最后BaseAction类代码如下:


   1. public class BaseAction extends DispatchAction   
   2. {   
   3.     protected SearchHandler sh=new SearchHandler();   
   4.   
   5.     protected void addResultMessage(HttpServletRequest request, String message)   
   6.     {   
   7.         ActionMessages messages=new ActionMessages();   
   8.         messages.add(Globals.MESSAGE_KEY, new ActionMessage(message));   
   9.         saveMessages(request,messages);   
  10.     }   
  11. }  

        最后代码效果请参考源代码。

        4)    重构注意事项:

               a) 每次要一点点的重构,万万不要一次重构很多地方。

               b) 每重构完一个地方要运行测试类来保证其正确性。

               c) 不要怕麻烦。在后期重构的优势就会越来越明显。

       到此为止,全部的测试与代码编写已经结束。还等什么,将已经做好的页面套上去吧,感受一下不用启动服务器来开发web应用程序的乐趣吧,感受测试驱动开发给你带来的开发思想的质的飞跃……

·          

·          

·          

·          

·         在Eclipse中使用StrutsTest进行Struts的单元测试[转载]

     下面在测试方法中就可以填写自己需要的东西了。如下面的例子:

package com.ezcross.SMS.common.struts.action;

import servletunit.struts.MockStrutsTestCase;

/**//**

 * @author paul.ping(wp.huang@ezcross.com)

 *

 * 类名:SMS10Test

 * 操作:

 */

public class LoginActionTest extends MockStrutsTestCase {

    /**//*

     * @see TestCase#setUp()

     */

    protected void setUp() throws Exception {

        super.setUp();

    }

    /**//*

     * @see TestCase#tearDown()

     */

    protected void tearDown() throws Exception {

        super.tearDown();

    }

    public void testDoExecute() {

        try

        {

            addRequestParameter("user_name","cka");

            addRequestParameter("passward","111111");

            setRequestPathInfo("/login");

            System.out.println("hava completed adding data");

            actionPerform();

            System.out.println("begin verify");

            verifyForward("dologin");

            verifyForwardPath("/Login.jsp");

            verifyNoActionErrors();

            System.out.println("end verify");

                        //assertNotNull(testObject.doExecute(null,null,null,null,null));

        }

        catch (Exception ee)

        {

            System.out.println(ee.toString());

        }

    }

}

 

填写完程序后,右击程序,选择run下的JUnit Test进行运行,如果没有错误的话则显示绿色 ,否则显示红色。

 

对程序的说明:

主要函数和作用:

-          setContextDirectory,设置web应用的根

-          setRequestPathInfo,设置request的请求

-          addRequestParameter,将参数和对应的值加入request中

-          actionPerform,执行这个请求

-          verifyForward,验证forward的名字是否正确

-          verifyForwardPath,验证forward的path是否正确

-          verifyNoActionErrors,验证在action执行过程中没有ActionError产生

-          verifyActionErrors,验证在action执行过程中产生的ActionError集合的内容

具体详细的内容请参见对应的javaDoc。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值