• [Struts]使用StrutsTestCase对Action进行单元测试简介


    目前,测试驱动开发正变得越来越流行,由于“存在的就是合理的”,这种开发方式必然有其优越之处。作为一个小小程序员,对新鲜技术的追求是工作的重要动力,相信大家都有同感吧。

    测试驱动开发是极限编程(XP)的重要组成部分,从字面上就可以看出,它是先有测试再有代码的。这听起来似乎有点奇怪,实际上,可以把测试用例当作需求,程序员的工作就是写出满足这种需求的代码,即让这些测试都能够通过。在刚刚写好测试用例的时候,由于还没有实际代码,因此这时运行测试的结果一定不会通过,随着代码的增加,越来越多的测试得以通过,最后全部通过。这时,基本上可以说系统的每个功能单元都是正确的,剩下的工作就是集成测试了。而这些测试用例的使命并未结束,因为代码会不断修改,我们需要经常(例如每天)运行测试来检验目前的代码是否能够通过测试。很明显,这种检验是完全自动化的,既快速有保证质量。

    在使用Struts构件的系统里,的每一个Action都可以看作一个功能单元,它们构成了系统的主体。(当然,你的业务逻辑并不一定都直接写在Action的execute方法中,但在该方法中会以一定方式调用这些逻辑。)StrutsTestCase(http://strutstestcase.sourceforge.net/)是JUnit的一个包装,它提供了非常方便的测试这些Action的方法。它提供两种测试方式:Mock(模拟对象)和Cactus(真实环境),目前我只试验了前者,发现效果很好。

    由于我已经写了一些代码,因此我进行的不能算是真正的测试“驱动”开发,我主要是把StrutsTestCase作为一种自动化的测试工具来用,起到保证代码质量的作用。

    举例来说,我有一个类名为SaveTeacherAction的Action,其所在模块名为teacher,访问路径为/save,与他相关联的是名为TeacherForm的ActionForm,(struts-config-teacher.xml)配置如下所示:

    <action
        attribute
    ="teacherForm"
        input
    ="/form/teacher.jsp"
        name
    ="teacherForm"
        path
    ="/save"
        scope
    ="request"
        type
    ="edu.pku.cc.democenter.teacher.action.SaveTeacherAction">
        
    <forward name="success" path="/list.do" redirect="true" />
    </action>

    SaveTeacherAction类中的execute方法如下,其中HibernateDAO是我自己写的用来进行持久化操作的包装类,BeauUtils是Jakarta commons包中的一个实用工具,可以在两个Bean类型对象的相同属性之间进行复制:

    public ActionForward execute(
        ActionMapping mapping,
        ActionForm form,
        HttpServletRequest request,
        HttpServletResponse response)
        throws Exception {

        HibernateDAO dao
    =HibernateDAO.getInstance(getServlet().getServletContext());
        TeacherForm teacherForm 
    = (TeacherForm) form;
        Teacher t
    =null;
        
        
    if("Create".equals(teacherForm.getAction())){
            t
    =new Teacher();
        }
        
    if("Edit".equals(teacherForm.getAction())){
            t
    =(Teacher)dao.findByCode(Teacher.class,teacherForm.getCode());
        }
        
        BeanUtils.copyProperties(t,teacherForm);
        
        dao.saveOrUpdate(t);
        
    return mapping.findForward("success");
    }

    下面,我要写一个测试用例来对这个Action进行测试。在Eclipse里使用StrutsTestCase非常简单,只需要在工程的classpath里包含strutstest-2.1.2.jar这个包以及junit的包就可以开始编写了。我为这个类起名为TestSaveTeacherAction,即Action类名前加上Test字样,所在包也与实际代码分开,使用edu.pku.cc.democenter.test的名称(与之对比,SaveTeacherAction的包名为edu.pku.cc.democenter.teacher.action,democenter是我们这个项目的名称)。

    现在来看一下TestSaveTeacherAction的内容:

    package edu.pku.cc.democenter.test;

    import servletunit.struts.MockStrutsTestCase;
    import edu.pku.cc.democenter.teacher.form.TeacherForm;

    public class TestTeacherAction extends MockStrutsTestCase{

        protected 
    void setUp() throws Exception {
            super.setUp();
            setConfigFile(
    "teacher","/WEB-INF/struts-config-teacher.xml");
        }

        protected 
    void tearDown() throws Exception {
            super.tearDown();
        }

        public 
    void testSaveTeacherAction_Create(){
            setRequestPathInfo(
    "/teacher","/save");
            TeacherForm form
    =makeForm();
            form.setAction(
    "Create");
            form.setCode(
    "test.create");
            setActionForm(form);
            actionPerform();
            verifyForward(
    "success");
        }
        
        public 
    void testSaveTeacherAction_Edit(){
            setRequestPathInfo(
    "/teacher","/save");
            TeacherForm form
    =makeForm();
            form.setAction(
    "Create");
            form.setCode(
    "test.edit");
            setActionForm(form);
            actionPerform();
            
            form.setAction(
    "Edit");
            form.setBirthDate(
    "1979-1-10");
            setActionForm(form);
            actionPerform();
            verifyForward(
    "success");
        }

        private TeacherForm makeForm(){
            TeacherForm form
    =new TeacherForm();
            form.setAction(
    "Create");
            form.setBirthDate(
    "1979-1-1");
            form.setCode(
    "test.001");
            form.setEmail(
    "test@test.com");
            form.setName(
    "test");
            form.setShortName(
    "CS");
            form.setTel(
    "62760000");
            
    return form;
        }
    }

    使用Mock方式的测试用例都继承servletunit.struts.MockStrutsTestCase这个类,setUp和tearDown方法分别是测试前后进行准备和善后工作的地方。要运行的测试方法都以test开头,系统会自动调用这些方法。

    由于SaveTeacherAction根据request中的action参数有两种运行方式:Create和Edit,所以我写了两个test方法对它们分别进行测试。这里要注意的是,这些test方法运行的顺序是不确定的,不要认为可以先运行create的测试,再以此为基础对刚刚create的对象进行edit,看testSaveTeacherAction_Edit方法的写法。

    我在setUp方法里指定了模块和对应的配置文件名称,如果没有模块可以省去这一步。在实际的testSaveTeacherAction_Create方法里,首先用setRequestPathInfo方法指定要测试的Action的路径和模块,如果没有模块可以用一个参数的同名方法。然后构造一个ActionForm,对于我的例子就是TeacherForm,为了简化代码,我写了一个makeForm方法来生成一个填好值的TeacherForm。用setActionForm将这个TeacherForm连接到Action,actionPerform方法通知执行Action操作。这时按照我们的设想,Action会将请求转发到一个名为success的Forward,所以我们使用verifyForward("success")方法验证是否进行了转发。在这一步如果失败,就表明此单元测试失败,否则为成功。

    testSaveTeacherAction_Edit方法与其类似,只是要注意在这个方法里要自己建立对象再修改,而不能使用testSaveTeacherAction_Create方法里建立的对象,因为这两个方法的执行顺序是不确定的。

    要在Eclipse里运行这个测试也很简单,先双击打开这个类,然后在Run菜单里选择Run As->JUnit Test就可以了,你会看到一个JUnit视图,里面有一个绿色的进度条,如果走到头还保持绿色表示所有的测试都成功,否则会变成红色,并在下面显示异常的堆栈信息。(成就感哦)

    好了,今天对StrutsTestCase作了一个很简单的介绍,我也是刚刚开始使用它,今后肯定还会遇到问题的,敬请关注后续报道。

    另,相关的一些文章可以在网上找到,作为入门很好,例如:

    http://plateau.sicool.com/article/tdd/strutstestcast_junit_tdd.htm

    我的感觉,遇到问题最好先找文档,养成习惯后不但解决问题快了,同时在看文档的同时还可以对其加深理解,何乐而不为呢。

  • 相关阅读:
    第一周学习进度
    四则运算
    添加课程
    继承和多态的动手动脑
    String 方法
    【CoreData】分页查询和模糊查询
    【CoreData】表之间的关联
    代码创建storyboard
    UIWindows&nbsp;使用注意
    UIApplicationDelegate
  • 原文地址:https://www.cnblogs.com/bjzhanghao/p/28221.html
Copyright © 2020-2023  润新知