分享
 
 
 

运用 DBUnit 进行高效的单元测试

王朝other·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

现实系统中通常会有一些具有外部依靠性的对象,这些对象和数据库或者其他对象存在诸多关联。假如我们对这样的对象编写单元和组件级测试的话,可以想象将是非常麻烦的一件事.因为这种外部依靠性的存在,使的我们很难将对象孤立出来进行测试。经常提及的白盒测试法,基本上就是通过控制对象的外部依靠性来达到隔离对象的目的,使的可以操作这些对象的状态和相关行为。

运用 模拟对象(mock objects)

或者stubs,就是一个控制对象外部依靠性的解决方案。通过隔离那些关联的数据库访问类,象JDBC的相关操作类,对于控制对象外部依靠性将是很有效的。但模拟对象的解决方案对一些非凡的应用系统架构就显得力不从心了,象那些运用了EJB的CMP(container-managed

persistence)或者 JDO(Java Data

Objects)的应用系统架构,在这些架构里,数据库的访问对象是在最底层的而且很隐蔽。

由Manuel Laflamme

编写的开放源代码的DBUnit架构体系,对于控制系统内部的数据库依靠性提供了一个非常不错的解决方案。他答应程序员在整个的测试过程中自由的治理控制数据库的状态,这很重要。利用DBUnit,在测试之前,我们可以给目标数据库植入我们需要的数据集,而且,在测试完毕后,数据库完全能够回溯到测试前的状态。

在很多成功的软件项目中,测试自动化往往是要害的层面。DBUnit答应开发人员创建测试用例代码,在这些测试用例的生命周期内我们可以很好的控制数据库的状态。而且,这些测试用例是很轻易实现自动化的。这样在测试过程中我们无须对它进行人工的干预,为人工干预造成的后果而担心就更没必要了。

简单介绍

配置使用DBUnit的第一步我们首先需要知道如何生成数据库schema,这个文件是XML格式的,其中包括了数据库的表及相关数据信息。

例如,这里有一个数据库表employee

,我们可以用SQL的形式这样将他表示出来。

而且,我们可以看到,一个简单的数据集可以这样表示

在DBUnit中,上面这个表和抽样数据信息可以用XML文件的形式这样表示:

<EMPLOYEE employee_uid='1'

start_date='2001-11-01'

first_name='Andrew'

ssn='xxx-xx-xxxx'

last_name='Glover' /

这个生成的XML格式的文件可以作为系统所需的所有种子文件(seed

files)的样本模版.

为相互关联的测试场景创建多个种子文件是一个很有效的策略,就象通过不同的数据库文件来区分隔离数据库状态是一个道理。多种子文件策略可以将我们的测试目标锁定到较小的范围,目标数据可以只针对数据库的表,而不是整个数据库。

为了给目标数据库植入不同的职员记录,我们需要的XML数据文件如下所示:

<?xml version='1.0' encoding='UTF-8'?

<dataset

<EMPLOYEE employee_uid='1'

start_date='2001-01-01'

first_name='Drew' ssn='000-29-2030'

last_name='Smith' /

<EMPLOYEE employee_uid='2'

start_date='2002-04-04'

first_name='Nick' ssn='000-90-0000'

last_name='Marquiss' /

<EMPLOYEE employee_uid='3'

start_date='2003-06-03'

first_name='Jose' ssn='000-67-0000'

last_name='Whitson' /

</dataset

现在,要让DBUnit和我们所需的数据库schema一起工作了,对于程序员来说,我们使用DBUnit进行测试可以有两种选择:通过直接编码方式进行测试或者与Ant结合.

编码方式

DBUnit框架提供了一个基本的抽象测试用例类,叫做DatabaseTestCase,它是JUnit框架中的基础类TestCase的子类。假如我们使用这个类必须首先实现两个钩子方法(hook

methods):getConnection()和getDataSet().

方法getConnection()需要返回一个IDatabaseConnection类型的对象,这个对象是一个基于普通JDBC连接的包装类。例如,下面的代码段演示了在mysql数据库环境下,IDatabaseConnection类型连接对象的创建方法。

protected IDatabaseConnection getConnection()

throws Exception {

Class driverClass = Class.forName("org.gjt.mm.mysql.Driver");

Connection jdbcConnection = DriverManager.getConnection(

"jdbc:mysql://127.0.0.1/hr", "hr", "hr");

return new DatabaseConnection(jdbcConnection);

}

方法getDataSet()返回一个IDataSet类型对象,其实,说白了,他就是我们先前提到的XML数据的种子文件的另一种表现形式。

protected IDataSet getDataSet() throws Exception {

return new FlatXmlDataSet(

new

FileInputStream("hr-seed.xml"));

}

有了这两个基本的方法以后,DBUnit就可以按照它预先缺省的行为工作了。DatabaseTestCase类提供了两个fixture(我叫它固件,不知仁兄同意否?)方法来控制测试前和测试后的数据库状态。这两个方法就是:

getSetUpOperation() 和 getTearDownOperation().

一种高效的实施方案就是让getSetUpOperation()方法执行REFRESH操作,通过这个操作,我们可以用种子文件中的数据去更新目标数据库里的数据。接下来,就是getTearDownOperation(),让他去执行一个NONE操作,也就是什么也不执行。

protected DatabaseOperation getSetUpOperation()

throws

Exception {

return DatabaseOperation.REFRESH;

}

protected DatabaseOperation getTearDownOperation()

throws

Exception {

return DatabaseOperation.NONE;

}

还有一种有效的方法就是在getSetUpOperation()方法中执行CLEAN_INSERT操作,这样首先会将目标数据库中与我们提供的种子文件一致的数据删除,然后将我们提供的数据插入到数据库中。这个实施顺序保证了我们对数据库的精确控制。

代码样例

在一个基于J2EE的人力资源系统中,我们很希望对某个数据操作周期实现测试自动化,这个操作周期包括职员的新增,检索,更新和删除。远程接口定义了下列的业务方法(为了简洁清楚,省略了方法中的throws子句).

//译者注:这里的EmployeeValueObject类型对象,译者认为是代表职员实体信息的对象。

public void createEmployee( EmployeeValueObject emplVo )

public EmployeeValueObject getEmployeeBySocialSecNum( String ssn )

public voidupdateEmployee( EmployeeValueObject emplVo )

public voiddeleteEmployee( EmployeeValueObject emplVo )

测试getEmployeeBySocialSecNum()方法

需要植入一条数据到目标数据库中,另外,测试deleteEmployee()方法和updateEmployee()方法时,同样也是在先前植入的这条记录的基础上进行。最后,测试类会首先利用createEmployee()方法创建一条记录,同时我们需要校验执行这个方法时,是否会有异常发生。

下面这个DBUnit种子文件,叫做"employee_hr_seed.xml",下面将用到这个文件。

<?xml version='1.0' encoding='UTF-8'?

<dataset

<EMPLOYEE employee_uid='1'

start_date='2001-01-01'

first_name='Drew' ssn='333-29-9999'

last_name='Smith' /

<EMPLOYEE employee_uid='2'

start_date='2002-04-04'

first_name='Nick' ssn='222-90-1111'

last_name='Marquiss' /

<EMPLOYEE employee_uid='3'

start_date='2003-06-03'

first_name='Jose' ssn='111-67-2222'

last_name='Whitson' /

</dataset

测试类 EmployeeSessionFacadeTest

,需要扩展DBUnit的基础类DatabaseTestCase并且必须提供对getConnection()和getDataSet()方法的实现,在getConnection()方法中将获得与EJB容器初始化时一样的数据库实例,getDataSet()方法负责读取上面提及的employee_hr_seed.xml文件的数据。

测试方法相当简单,因为DBUnit已经为我们处理了复杂的数据库生命周期任务。为了测试getEmployeeBySocialSecNum()方法,只需要简单的传递一个存在于种子文件中的社保代码号即可,比如

"333-29-9999".

//译者注:EmployeeFacade 类型对象,译者认为是代表底层数据库数据的映射体

public void testFindBySSN() throws Exception{

EmployeeFacade facade = //oBTain somehow

EmployeeValueObject vo =

facade.getEmployeeBySocialSecNum("333-29-9999");

TestCase.assertNotNull("vo shouldn't be null", vo);

TestCase.assertEquals("should be Drew",

"Drew", vo.getFirstName());

TestCase.assertEquals("should be Smith",

"Smith", vo.getLastName());

}

为了确保操作周期中的创建职员方法createEmployee()没有问题,我们只需简单的执行一下这个方法,然后校验一下看有没有异常抛出,另外,下一步我们要做的就是在这条新增的记录上进行查找操作,看是否可以找到刚创建的记录。

public void testEmployeeCreate() throws Exception{

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有