83477102 2009-06-01
想写这篇文章很久了,因为 Seam 下的单元测试一直存在一些配置方面的问题,而且 Seam 框架提倡最多的是整合测试。所以关于单元测试,无论是 Seam 的参考手册还是其他参考书(Seam In Action, etc.)里都没有详细介绍和例子。总所周知,单元测试是保证质量或 TDD 必不可少的部分,对项目的重要性不言而喻。本文以实例说明了 Seam 的单元测试如何进行,有不对之处请大家指出 :-)
一. Seam 下的单元测试的难点与问题
1. Seam 框架依赖于容器环境
不只是 Seam,现在的 Web 框架很少有可以在纯 JavaSE 环境中可运行的,所以脱离了容器环境,框架是不能运行的,其实也是没有意义的。只要涉及到了容器,就会带来很多的问题,而且因为容器的不同,问题错综复杂。
2. 容器内 / 容器外测试的复杂度
这里说的容器内测试就是在部署应用后在容器的环境里拿到应用的上下文,也就是在应用运行时在同一环境(容器内)拿到待测实例并进行测试。换句话说,测试用例与实现都是运行在容器的环境里。而容器外测试则是测试环境通过远程访问容器,拿到容器内的 Remote Seam Components / Remote EJB Session Beans 实例,从而在容器外的测试环境下进行测试。
3. JBoss 社区产品的整体性
Seam 是 JBoss 的,jBPM 是 JBoss 的,等等 Seam 相关的依赖环境都是 JBoss 的。所以,容器不是 JBoss 的的话,两个字:麻烦。虽然现在的 Seam(ver 2.1.1) 在文档 / 示例中说明了如何在非 JBoss AS 中配置与使用 Seam,但据笔者目前的尝试,要想顺利使用 Seam 的 Advanced 功能,JBoss AS / HIbernate 不用都不行。这也要求了要做 Seam 的单元测试,就必须对很多 JBoss 产品有一定的了解。
二. 解决问题
归根结底,Seam 下的单元测试只所以不好做,还是难在了配置上。要配置好一个‘类容器’的环境才能让 Seam 跑起来。
1. 搭建‘类容器’环境
从配置上来说,我们首先要搭建一个容器环境。把下载下来的 Seam 解压,把 bootstrap 里面找到 conf 与 deploy 这两个目录并 copy 到测试环境目录下。在测试环境目录下建立 WEB-INF 目录,并把 Seam 的核心配置文件 components.xml 放置到这里,还有 JSF、Web 部署描述符等需要的都放置到 WEB-INF 目录里。
2. 在测试用例中拿到待测 Seam 组件实例
从代码上来说,拿到待测组件实例是关键。在测试代码中,可以通过 org.jboss.seam.Component.getInstance() 方法从 Seam 框架中获取需要的组件实例,这是单元测试能否成功的关键。
3. 初始化 Seam 框架
在测试代码中需要手动初始化 Seam 框架与应用,测试结束后也同样需要手动结束框架与应用,其都是通过 org.jboss.seam.context.Lifecycle 进行操作的。
4. 测试框架的选择
这不是相对于 Seam 单元测试的关键问题,但是,恰但地选择测试框架对于项目而言是很重要的。总所周知,目前最常用的两个测试框架 JUnit 与 TestNG 各有千秋,这里我简单总结一下:
JUnit:适合小型项目,对于简单的单元测试可以很好的发挥其‘小而强大’的优势,主流 IDE 都有其功能或插件。但要进行整合测试(集成界面)就困难了。
TestNG:适合任何项目,IDE 支持不是很好,但是 JUnit 能做的它都能做,而且更细致,适用场景更广泛。
三. 示例
笔者是用 NetBeans IDE 与 Maven 搭建的项目,Seam 下的单元测试的具体配置和示例代码片断如下:
初始化:
if (!Lifecycle.isApplicationInitialized()) {
Lifecycle.beginApplication(new HashMap());
new Initialization(new MockServletContext()).create().init();
Lifecycle.beginCall();
}
获取待测组件实例:
processDefTransformer = (ProcessDefTransformService) Component.
getInstance(ProcessDefTransformer.class);
assertNotNull(processDefTransformer);
结束:
Lifecycle.endApplication();