JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子(十二)
1.引言
测试驱动开发(Test-Driven Development)的基本思路就是通过测试来推动整个开发的进行。设计思路定下来以后,先编写测试程序,然后再实现被测试的功能。这个习惯的形成将显著地提高软件的质量。
针对服务层的单元测试,本项目构建了一个完整的测试环境。本文介绍测试环境构建的设计思路。
2.单元测试应该测试什么?
在 这篇文章中,介绍了本项目的分层设计方法。作为设计原则,远程外观和Servlet中不应该有太多的业务逻辑,具体功能必须由服务层实现。因此我认为没有必要对远程外观和Servlet进行测试。
我在本项目中提倡的领域模型层的设计,基本上可以归为所谓“贫血领域模型”( Anemic Domain Model)这种架构模式,因为没有太多的领域逻辑,所以也不必去对它们做单元测试了。
最后,真正需要单元测试的就剩下了服务层!本项目围绕服务层构建了一个完整的单元测试环境。
3.测试环境设计
由于遵循POJO without EJB设计原则,本项目中的单元测试是在完全脱离Seam框架下进行的。测试环境设计的要点说明如下:
(1)测试数据库和开发数据库分开,用Ant目标切换:
xml 代码
- <target name="copy-config-dev" >
- <concat destfile="WEB-INF/src/hibernate.cfg.xml">
- <filelist dir="config/db" files="head.xml" />
- <filelist dir="config/db" files="datasource-dev.xml" />
- <filelist dir="config/db" files="sample.xml" />
- <filelist dir="config/db" files="end.xml" />
- concat>
- target>
- <target name="copy-config-test" >
- <concat destfile="WEB-INF/src/hibernate.cfg.xml">
- <filelist dir="config/db" files="head.xml" />
- <filelist dir="config/db" files="datasource-test.xml" />
- <filelist dir="config/db" files="sample.xml" />
- <filelist dir="config/db" files="end.xml" />
- concat>
- target>
程序员需要自己手工配置好 config/db 目录下的两个数据源配置文件,datasource-dev.xml 用于开发,datasource-test.xml用于测试。
(2)为每一个子系统设计一个 XXXTestCase 类,全部服务层测试类扩展这个类。XXXTestCase 类的主要任务是准备测试数据:
java 代码
- public class SampleTestCase extends BaseTestCase {
- @BeforeMethod
- @Override
- public void begin() {
- super.begin();
- initTableData();
- }
- /**
- * 单元测试前让数据库表处于初始状态
- */
- protected void initTableData() {
- exec("DELETE FROM Booking");
- exec("DELETE FROM Customer");
- exec("DELETE FROM Hotel");
- exec("DELETE FROM T_NextId");
- }
- /**
- * 准备测试数据:Customer
- */
- protected void insert2User() {
- exec("insert into Customer (username, password, name) values ('gavin', 'foobar', 'Gavin King')");
- exec("insert into Customer (username, password, name) values ('demo', 'demo', 'Demo User')");
- }
- 。。。
- }
我采用了最灵活的一种方式来准备测试数据,就是SQL语句。由于Hibernate会生成数据库表之间的参照完整性约束, 因此,程序员在编写SQL脚本时应该考虑到这一点。
(3)服务层的单元测试程序,由于继承了 XXXTestCase 类,可以集中于要测试的业务逻辑,例如:
java 代码
- public class UserServiceTest extends SampleTestCase {
- private UserService _userService;
- @BeforeClass
- @Override
- public void init() {
- super.init();
- _userService = new UserService();
- }
- @BeforeMethod
- @Override
- public void begin() {
- super.begin();
- _userService.setSession(session);
- }
- @Test
- public void canLogin() {
- insert2User();
- assert _userService.login("demo", "demo");
- assert _userService.getUser().getUsername().equals("demo");
- assert !_userService.login("demo", "demo2");
- }
- 。。。
- }
4.单元测试编程时需要注意的问题
编写单元测试程序时,需要注意下列问题:
(1)作为服务层设计的原则之一,禁止事务提交行为,因此,需要在单元测试方法中手工提交事务,如:
java 代码
- @Test
- public void canChangePassword() {
- insert2User();
- User user = _userService.find("demo");
- _userService.setUser(user);
- _userService.changePassword("demo2");
- session.flush(); //使事务提交
- assert _userService.find("demo").getPassword().equals("demo2");
- }
(2)为了模拟Seam框架的对象注入,在服务层类中,需要为单元测试专门额外添加 setter 方法,例如:
java 代码
- @BeforeMethod
- @Override
- public void begin() {
- super.begin();
- _hotelService.setSession(session); //额外增加了setSession方法,专门用于单元测试
- }
5.结语
本项目所用的单元测试环境构建方法,是我对以往项目经验的基础上设计的,经过实践检验是可行的。
这是本系列文章的最后一篇。下面是所有文章的完整列表:
(1) 下载示例项目并安装运行
(2) 建立Eclipse开发环境
(3) 熟悉项目中与JSF相关内容
(4) 重新认识JS
(5) ExtJS之表单(Form)
(6) ExtJS之布局(Layout)
(7) ExtJS之网格(Grid)
(8) Java后台和前台的通讯机制
(9) Seam框架简化Java开发
(10) 分层架构设计
(11) 安全性
(12)单元测试