DbUnit测试一 数据库测试挑战
本文翻译自《JUnit in Action 2nd Edition》第十六章,大家可以查看附件^_^。
主要有以下几个内容:
1. 数据库测试挑战;
2. 介绍DbUnit;
3. 高级DbUnit测试技术;
4. DbUnit最佳测试实践。
Dependency is the key problem in software development at all scales….
Eliminating duplication in programs eliminates dependency.
—Kent Beck, Test-Driven Development: By Example
(依赖是各种规模软件开发里的关键问题......在程序中通过消除重叠消除依赖)
持久化层(简单地讲就是:数据库访问代码)无疑是任何企业项目最重要的部分之一。且不说它的重要性,持久化层难于做单元测试,主要因为以下几点:
1. 单元测试必须实行代码孤立;但是持久层需要与外部实体(数据库)相互作用。
2. 单元测试必须容易写和运行;但是访问数据库的代码可能比较复杂。
3. 单元测试必须能够快速运行;但是数据库访问比较慢。
我们把这些问题叫做数据库单元测试阻抗不匹配--引用对象/关系阻抗不匹配(它描述了使用面向对象语言去写程序时,用关系数据库持久化数据的困难)。
数据库测试不匹配能通过使用专门的工具减少到最低,其中有个工具就是DbUnit。在这里,我们展示了DbUnit怎样去测试数据数据库代码,不仅描述了它的基本思想,也奉献了一些更好的使用方法,并且使代码更容易维护。
一、数据库单元测试阻抗不匹配
让我们更深入地看看构成数据库阻抗不匹配的三个问题。
1.1 测试必须实现代码孤立
严格地说,执行数据库访问的代码测试不是单元测试,因为它依赖于外部实体-数据库。那我们应该叫它什么呢?集成测试?功能测试?非单元测试?
答案就是:没有秘籍。也就是说,数据库测试依赖于环境,可以使用很多种合适的方式。
事实上,数据库访问代码能够被运用在单元和集成测试里。
●单元测试可用作测试直接操作数据库的类(例如DAOs)。这样的测试保证这些测试类执行了实际的SQL语句,加载了正确的对象等等。虽然这些测试依赖于外部环境(例如数据库或者持久化框架),但是他们保证了一个更大的程序的基础(因此是单元)。
●类似地,测试更高层(像Facades)也可以写单元测试,没有必要访问数据库——在这些测试里,可以通过mock或者stub模拟持久化层。
●即使持久层和更高层的单元测试都具备了,访问数据库的集成测试仍然是必需的,因为有些情形仅仅发生在一方到另一方的场景(比如经常出现在JPA应用程序里的可怕的延迟实例化异常)。
1.2 单元测试必须容易写和运行
不管公司、项目经理或者技术领导称赞单元测试多少次——如果它们不容易写和运行,开发人员就会抵制它。何况敲访问数据库的代码也不是一件吸引人的任务——不得不写那烦人的SQL语句,参杂多个嵌套的try/catch/finally代码,转换各种SQL类型。
因此,为了让数据库单元测试快速展开,必须减轻开发人员的“数据库压力”。幸运的是,有一些工具做到了,比如DbUnit就是其中之一。
1.3 单元测试必须快速运行
假如你克服了上面的两个问题并且有令人满意的配置环境,拥有数以百计的访问数据库的单元测试对象,而且开发人员也容易添加新的。所有的看起来非常好,但是当开发人员运行构建时(他们一天应该会构建很多次,至少在更新他们的workspase时和提交更改到源码控制系统前),需要10分钟去完成,其中9分钟都在运行数据库测试。你应该怎样做呢?
这是最难的问题,它也并不总是可以解决的。例如:由于数据库访问本身所引起延迟,因为数据库很可能是在远程服务器上,被几十个用户访问。一个可能的解决办法就是使这个数据库更接近开发人员,通过使用嵌入式数据库(如果使用标准的SQL可以切换一个数据库),或者本地安装一个精简版的数据库。
定义:嵌入式数据库
嵌入式数据库是一个绑定在应用程序内部的数据库,而不被外部服务器(一般情况下)管理。对于JAVA应用程序,有很多嵌入式数据库可以使用,他们大多数是开源的——比如HSQLDB(http://hsqldb.org), H2(http://h2database.com), Derby(http://db.apache.org/derby), 和JavaDB(http://developers.sun.com/javadb). 嵌入式数据库的基本特征是它被应用程序管理,但不是用编写应用程序的语言所写。例如:HSQLDB和Derby支持客户端/服务器模型(除了可以选择嵌入式之外),然而SQLite(它是基于C语言的产品)也可以嵌入到JAVA应用程序中。
在下一个部分,我们将看DbUnit是怎样解决数据库单元测试不匹配的(以及在较小的程度上,嵌入数据库)。