阅读提要 StrutsTestCase是一个强有力的易于使用的针对Struts行为的测试框架。StrutsTestCase,并与传统型JUnit测试相结合,将会带给你一个相当高的测试覆盖率并提高你的产品的可靠性。
一、引言
StrutsTestCase是一个用于测试Struts行为的基于Junit的测试框架。假如你使用Struts,那么你会注重到它可以提供给你一种轻易而有效的方式来测试你的应用程序的Struts行为类。
典型的J2EE应用程序都是分层构建的,如图1所示。
·DAO层封装了数据库存取。Hibernate映射和对象类,Hibernate查询,实体EJBs,或一些其它的实体-关系持续性技术都可以在这一层找到。
·商业层包含更高级的商业服务。理想地,这个商业层将是相对独立于数据库实现。在这个层上经常使用会话EJBs。
·描述层包含为用户显示应用程序数据并解释用户请求。在一个Struts应用程序中,这一层典型地使用jsp/JSTL页面来显示数据并且使用Struts行为来解释用户查询。
·客户层基本上是运行于用户机器上的web浏览器。客户端逻辑(例如,javascript)有时被放在这里,尽管很难对其进行有效地测试。
图1.典型的J2EE架构
DAO和商业层的测试或者可以通过使用经典的JUnit测试或者使用各种JUnit扩展来进行,具体依靠于架构的实现细节。DbUnit是一种用来进行数据库单元测试的良好选择。
另一方面,测试Struts行为总是很困难的事情。即使在商业层严格地限制于商业层的构建时,Struts行为也总要包含重要数据校验,转换和流程控制代码。不对Struts行为进行测试将会在代码覆盖率上留下一道很脏的鸿沟。StrutsTestCase会让你填充这条鸿沟。
对行为层进行单元测试还带来其它一些益处:
·可以更好地规划视图和控制层,从而使之更为简单清楚。
·更轻易重构行为类。
·避免冗余的未使用的行为类。
·测试实例有助于对行为层进行归档-这在创建屏幕时是很有用的。
上面是基于测试开发的典型好处,并且它们可以应用于在各种情况下使用的Struts行为层。
二、StrutsTestCase简介
StrutsTestCase工程提供了一种灵活又方便的方法来从JUnit框架内测试Struts行为。它能够使你对你的Struts行为进行白色盒子测试-通过在调用行为后建立请求参数并检查结果Request或session的状态。
StrutsTestCase答应或者是一个模拟测试方式-这时框架模拟web服务器容器,或者是一个容器内方式-这时使用Cactus框架来从服务器容器(例如Tomcat)内部运行测试。一般地,我比较喜欢模拟测试方式,因为它更为轻量级的且运行更快些,并因此答应较宽松的开发周期。
所有的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())。然后,我们用actionPerform()来调用行为类。这将验证Struts配置并且调用相应的行动类,但是将不测试该行为的实际所做。为此,我们需要验证行动的结果。