`
lujar
  • 浏览: 511915 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

使用StrutsTestCase进行测试驱动开发

阅读更多

  StrutsTestCase是用于测试Struts动作的强大易用的测试框架。结合传统的JUnit测试,Struts
StrutsTestCase将为您提供高覆盖率的测试,从而提高产品可靠性。

   StrutsTestCase是基于JUnit的Struts动作测试框架。Struts将为测试应用程序的Struts动作类提供简便有效
的方法。

   典型的J2EE应用程序是分层构建的,其结构如图1所示:

  • DAO层封装数据库访问。其中包括Hibernate映射、Object类、Hibernate查询、实体EJB或其他实体-关系持久化技术。
  • 业务层包含更多高级业务服务。理想状态下,业务层相对独立于数据库实现。这一层常常用到EJB事务。
  • 表示层向用户展示应用程序数据,并解释用户请求。在Struts应用程序中,该层通常使用JSP/JSTL页面显示数据,并借助于Struts动作解释用户的查询请求。
  • 客户端层主要是用户机器上运行的web浏览器。客户端逻辑(比如JavaScript)有时候就置于该层,尽管
    很难对其进行有效的测试。

图1:典型的J2EE架构
图1:典型的J2EE架构

   视具体架构,DAO及业务层可使用JUnit经典测试法或者各种JUnit扩展工具进行测试。DbUnit就是进行数
据库单元测试的好选择。(更多DbUnit信息请参见Andrew Glover所著的《Effective Unit Testing with DbUnit》)
   另一方面,通常很难对Struts动作进行测试。即使业务逻辑完全限定于业务层,Struts动作通常还是会包含
重要的数据验证、数据转换和数据流控制代码。如果不对Struts动作进行测试,那么将在代码覆盖率方面留下很
大空白。而StrutsTestCase将填补这些空白。

   对动作层进行单元测试还会带来其他的一些好处:

  • 视图层及控制层设计起来更容易,通常也更为简洁明了。
  • 更易于重构动作类。
  • 有助于避免冗余和无用的动作类。
  • 测试用例有助于编写动作层文档,这些文档在编写JSP页面时可以起到帮助作用。

  这些是测试驱动开发的一些常见优点,这些优点适用于Struts动作层,也适用于其他的一些地方。

StrutsTestCase简介

  StrutsTestCase提供了在JUnit框架内测试Struts动作的灵活便利的方法。可以通过设置请求参数并检查调
用动作后生成的Request或Session状态的方式,来对Struts动作进行白盒测试。

   StrutsTestCase支持使用框架来模拟web服务器容器的模拟测试方法,或者在服务器容器(如Tomcat)内
使用Cactus框架进行测试的容器内测试方法。一般来说,我更喜欢模拟测试方法,因为这种方法更为轻量级,
运行更快,从而可以实现更紧凑的开发周期。

   所有StrutsTestCase单元测试类均由模拟测试的MockStrutsTestCase或者容器内测试的CactusStrutsTestCase派生。由于模拟测试方法设置更简单,运行更快,所以在这里我们将主要关注模拟测试
方法。

StrutsTestCase实践

  为了使用StrutsTestCase测试该动作,我们将创建一个扩展MockStrutsTestCase类的新类。该类提供一些
方法,用于构建模拟HTTP请求,调用相应的Struts动作,并在动作完成后验证应用程序的状态。

   设想一个用于安排住宿的在线数据库,它带有一个复合条件搜索函数。搜索函数通过/search.do动作来实
现。该动作将根据特定条件执行复合条件搜索,并将搜索结果列表置于名为results的属性中,该属性的作用域
为请求范围内。比如,下面的URL将会显示法国的所有住宿地列表。

/search.do?country=FR

  现在假设我们使用测试驱动方法来实现该方法。编写动作类,更新Struts配置文件。编写测试用例,测试该
动作类(空)。采用严格的测试驱动开发方法,首先编写测试用例,再实现符合测试用例的代码。在实际情况中,
具体顺序视测试代码不同而有所不同。

   初始的测试用例看起来应该如下:

public void testSearchByCountry() {
  setRequestPathInfo("/search.do");
  addRequestParameter("country", "FR");
  actionPerform();
}

  在这里,我们设置调用路径(setRequestPathInfo()),并添加请求参数(addRequestParameter())。

   接下来,使用调用动作类。这样将会验证Struts配置并调用相应的动作类,但是并不会对动作的实际功能
进行测试。为了测试动作的实际功能,我们需要验证动作结果。

public void testSearchByCountry() {
  setRequestPathInfo("/search.do");
  addRequestParameter("country", "FR");
  actionPerform();
  verifyNoActionErrors();
  verifyForward("success");
  assertNotNull(request.getAttribute("results"));
}

  在这里,我们要验证三点:

  • 无ActionError消息(verifyNoActionErrors())。
  • 返回了success转向路径。
  • results属性置于请求范围内。

  如果使用Tiles框架,也可以通过verifyTilesForward()核查success转向是否指向的正确tiles定义。

public void testSearchByCountry() {
  setRequestPathInfo("/search.do");
  addRequestParameter("country", "FR");
  actionPerform();
  verifyNoActionErrors();
  verifyTilesForward("success","accommodation.list.def");
  assertNotNull(request.getAttribute("results"));
}

  在实践中,我们也许希望对测试结果进行特定于业务的测试。例如,如果results属性预计为包含了100个
Hotel域对象的List(列表),而我们需要确认列表上的所有宾馆均在法国。为了实现此类测试,代码必须非常
类似于标准JUnit测试:

public void testSearchByCountry() {
  setRequestPathInfo("/search.do");
  addRequestParameter("country", "FR");
  actionPerform();
  verifyNoActionErrors();
  verifyForward("success");
  assertNotNull(request.getAttribute("results"));
  List results  = (List) request.getAttribute("results"); 
  assertEquals(results.size(), 100);
  for (Iterator iter = results.iterator(); iter.hasNext();) {
       Hotel hotel = (Hotel) iter.next();
       assertEquals(hotel.getCountry, TestConstants.FRANCE);
       ...
  }
}

  当遇到更为复杂的测试情况时,您也许希望测试一系列动作。比如,假设用户搜索所有法国宾馆,然后单击
任一搜索结果查看详细情况。假设我们有一个显示特定宾馆详细情况的Struts动作,该动作可被调用如下:

/displayDetails.do?id=123456

  使用StrutsTestCase,我们可以在同一测试内轻松模拟一系列动作。用户可以搜索法国所有宾馆,并单击
查看详情。

public void testSearchAndDisplay() {
  setRequestPathInfo("/search.do");
  addRequestParameter("country", "FR");
  actionPerform();
  verifyNoActionErrors();
  verifyForward("success");
  assertNotNull(request.getAttribute("results"));
  List results  = (List) request.getAttribute("results"); 
  assertEquals(results.size(),100);
  Hotel hotel = (Hotel) results.get(0);
  setRequestPathInfo("/displayDetails.do");
  addRequestParameter("id", hotel.getId());
  actionPerform();
  verifyNoActionErrors();
  verifyForward("success");
  Hotel hotel = (Hotel)request.getAttribute("hotel");
  assertNotNull(hotel);
  ...
}

测试Struts错误处理

  错误处理测试非常重要。假设我们想测试给出错误国家代码时应用程序是否有良好的错误应对能力。
我们编写新的测试方法,使用verifyActionErrors()来检查Struts返回的错误信息(ErrorMessages):

public void testSearchByInvalidCountry() {
  setRequestPathInfo("/search.do");
  addRequestParameter("country", "XX");
  actionPerform();
  verifyActionErrors(new String[] {"error.unknown,country"});
  verifyForward("failure");
}

  有时候我们想在ActionForm对象中直接验证数据。我们可以使用getActionForm()来实现,如下例所示:

public void testSearchByInvalidCountry() {
  setRequestPathInfo("/search.do");
  addRequestParameter("country", "XX");
  actionPerform();
  verifyActionErrors(new String[] {"error.unknown,country"});
  verifyForward("failure");
  SearchForm form = (SearchForm) getActionForm();
  assertEquals("Scott", form.getCountry("XX"));        
}

  在这里,我们验证了错误发生后,错误国家代码在ActionForm中得到适当的保存。

定制测试环境

  有时,我们需要重写setUp()方法,它可以让我们指定各种非默认的配置选项。在这个例子中,我们使用另
一个struts-config.xml文件,并将XML配置文件验证设为无效:

public void setUp() { 
  super.setUp();
  setConfigFile("/WEB-INF/my-struts-config.xml");
  setInitParameter("validating","false");
}

一级性能测试

  测试动作或一系列动作是测试响应时间是否在可接受的范围之内的极佳方法。通过对Struts动作进行测试,
我们可以检查整个服务器端的性能(当然不包括JSP页面生成)。好的方法是在单元测试层次进行一些一级性能
测试,从而快速分离并排除性能问题,并将解决方法整合到编译过程以避免性能减退。

   下面是我用于一级Struts性能测试的一些基本原则:

  • 尽可能多地使用组合条件进行多条件查询,以验证索引定义的正确性。
  • 进行大数据量的查询测试(该查询返回大量结果),以检验响应时间及结果分页(如果有的话)。
  • 进行单次及重复查询测试(在使用缓存策略的情况下检查缓存性能)。

  一些开源库可以为性能测试提供帮助,比如Mike Clark创建的JUnitPerf。然而,这些数据库与
StrutsTestCase的集成比较麻烦。很多情况下,一个简单的计数器就可以帮助解决这个问题。下面是进行一级
性能测试的简单且有效的做法:

public void testSearchByCountry() {
  setRequestPathInfo("/search.do");
  addRequestParameter("country", "FR");
  long t0 = System.currentTimeMillis();
  actionPerform();
  long t1 = System.currentTimeMillis() - t0;
  log.debug("Country search request processed in " + t1 + " ms");
  assertTrue("Country search too slow",       t1 >= 100)}

结束语

  一般而言,单元测试是敏捷编程方法的重要组成部分,对于测试驱动开发来说尤其如此。StrutsTestCase
提供了对Struts动作进行单元测试的简单且有效的方法,而这类测试很难通过JUnit实现。

 

分享到:
评论

相关推荐

    StrutsTestCase工程例子

    StrutsTestCase是一个专门为Struts应用程序设计的测试框架,它允许开发者对Action类进行单元...通过深入研究这个工程例子,你可以掌握使用StrutsTestCase进行单元测试的技巧,为你的Struts项目带来更强大的测试支持。

    StrutsTestCase-2.1.4(含文档、源码、官方示例).rar

    StrutsTestCase是Apache Struts框架的一个扩展,它提供了一种集成测试工具,使得开发者能够方便地对基于Struts的应用程序进行单元测试和功能测试。这个压缩包“StrutsTestCase-2.1.4(含文档、源码、官方示例).rar...

    strutsTestCase所需要用到的jar

    strutsTestCase所需要用到的jar org.springframework.core-3.1.2.RELEASE.jar spring-test.jar struts2-junit-plugin-2.3.16.3.jar xmlbeans-2.3.0.jar xmlpull-1.1.3.1.jar xstream-1.4.2.jar xwork-core-2.3.16.3....

    Jakarta Struts Live

    - **使用StrutsTestCase(Cactus Mode)**:解释了如何在Cactus模式下使用StrutsTestCase进行测试,该模式可以与Servlet容器集成,提供更接近实际运行环境的测试体验。 - **使用jWebUnit测试JSP**:介绍了如何使用...

    Checked and Unchecked Exception

    在Java编程语言中,异常处理是一项关键特性,用于在程序执行过程中捕获并处理错误或非正常情况。...在使用StrutsTestCase或其他工具进行开发和测试时,正确处理这两类异常是确保代码质量、提高软件可靠性的重要手段。

    Struts2框架单元测试代码

    在Struts2中,我们通常使用JUnit作为单元测试工具,结合Mockito等库来模拟依赖,进行隔离测试。 首先,了解Struts2的执行流程:请求到达Servlet容器后,通过StrutsPrepareAndExecuteFilter转发到Struts2的核心拦截...

    JakartaStrutsLive

    - **Cactus模式**:介绍Cactus模式下的StrutsTestCase使用方法。 #### 使用jWebUnit测试JSP - **功能测试**:讲解如何借助jWebUnit工具进行JSP页面的功能测试。 ### 工作于ActionForms和DynaActionForms #### 定义...

    struts2-junit-plugin-2.1.6.jar

    在使用`struts2-junit-plugin`时,开发者可以创建一个继承自`StrutsTestCase`的测试类,这个基类提供了对Struts2环境的模拟,使得测试无需依赖实际的Web服务器。测试用例可以通过`setUp()`方法设置必要的环境,然后...

    struts2-junit-plugin-2.1.8.1.jar

    Junit则是Java编程语言中最常用的单元测试框架,它简化了对代码进行测试和调试的过程。 `struts2-junit-plugin-2.1.8.1.jar` 是一个特定版本的Struts2 JUnit插件,它的版本号是2.1.8.1。这个插件允许开发者在JUnit...

    struts面试题大全.doc

    - ActionForms不易用,不支持单元测试,需要依赖StrutsTestCase进行集成测试。 2. **实现MVC的方式**: - Struts使用JSP作为视图(View),ActionServlet作为控制器(Controller),JavaBeans作为模型(Model)。 - ...

    Struts2和Struts1的一些区别

    - **单元测试的支持**:在Struts1中,由于Action对象与Servlet API紧密耦合,因此对其进行单元测试时通常需要模拟整个Web环境,例如使用StrutsTestCase库提供的Mock对象。而在Struts2中,Action对象更加独立,可以更...

    appfuse开发文档

    5. **测试与部署**:使用内置的测试框架如JUnit和Cactus进行单元测试,完成开发后,可以方便地将应用部署到Tomcat等Servlet容器中。 AppFuse是一个强大的工具,尤其适合初学者和经验丰富的开发者快速启动新项目。...

    Struts的高级应用

    4. **StrutsTestCase**:StrutsTestCase是Struts提供的一个单元测试框架,它允许开发者对ActionForm、Action和ActionForward进行测试,确保这些组件在实际运行前功能正确。使用StrutsTestCase,可以编写模拟HTTP请求...

Global site tag (gtag.js) - Google Analytics