dbunit是一个基于junit扩展的数据库测试框架。它提供了大量的类对与数据库相关的操作进行了抽象和封装,虽然在80%的情况,你只需使用它极少的api。它通过使用用户自定义的数据集以及相关操作使数据库处于一种可知的状态,从而使得测试自动化、可重复和相对独立。虽然不用dbunit也可以达到这种目的,但是我们必须为此付出代价(编写大量代码,测试及维护),既然有了这么优秀的开源框架,我们又何必再造轮子。

  • dbunit的原理

dbunit的与单元测试相关的两个最重要的核心是org.dbunit.database.IDatabaseConnection org.dbunit.dataset.IDataSet ,前者是产品代码使用的数据库连接的一个简单的封装,后者是对单元测试人员自定义的数据集(通常以xml文件的形式存在,且xml文件的格式也有好几种)的封装。

还有一个很重要的咚咚就是org.dbunit.operation.DatabaseOperation该类是一个抽象类代表了对数据库的操作,例如CUD以及其组合等, 它采用了退化的工厂模式,可直接通过它获取其具体的子类(代表具体的某种操作)如下:

DatabaseOperation.UPDATE

DatabaseOperation.DELETE

DatabaseOperation.DELETE_ALL

DatabaseOperation.TRUNCATE

DatabaseOperation.REFRESH

DatabaseOperation.CLEAN_INSERT

DatabaseOperation.NONE

工作流程如下:

1)testcase.setup--->testcase.getConnection-->getDataSet----->operation.execute(
通常DatabaseOperation.CLEAN_INSERT)

2)testcase.testSomeMethod---->dao.someMethod

3)testcase.teardown---->operation.execute(
通常DatabaseOperation.DELETE_ALL或者DatabaseOperation.NONE)

  • 实战

以一个真实的系统(share@mofile)为例,

  1. 建立一个测试数据库
  2. 写自定义的数据

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

<dataset>

<FileType typeId='1' typeName='type1' />

<FileType typeId='2' typeName='type2' />

<FileType typeId='3' typeName='type3' />

<UserInSharedSystem userId='1' loginName='2' userNo='a' />

<DefaultFile fileId='1' fileName='a1' fileSize='10' fileStatus='1'

pickupCode='4414402888619758' releaseDate='2006-1-31 16:17:18'

storageFileHome='solar' storageFileId='1' userId='1' typeId='1'

description='ss' expiredDate='2006-1-31 16:17:18'

uploadDate='2006-1-31 16:17:18' extName='exe' totalPoints='0'

currentMonthPoints='0' lastMonthPoints='0' />

<DefaultFile fileId='2' fileName='a2' fileSize='20' fileStatus='1'

pickupCode='4414402888619759' releaseDate='2006-1-31 16:17:18'

storageFileHome='solar' storageFileId='2' userId='1' typeId='2'

description='ss' expiredDate='2006-1-31 16:17:18'

uploadDate='2006-1-31 16:17:18' extName='exe' totalPoints='0'

currentMonthPoints='0' lastMonthPoints='0' />

<DefaultFile fileId='3' fileName='a3' fileSize='30' fileStatus='1'

pickupCode='4414402888619768' releaseDate='2006-1-31 16:17:18'

storageFileHome='solar' storageFileId='3' userId='1' typeId='3'

description='ss' expiredDate='2006-1-31 16:17:18'

uploadDate='2006-1-31 16:17:18' extName='exe' totalPoints='0'

currentMonthPoints='0' lastMonthPoints='0' />

<FileTag tagId='1' tagName='t1' />

<FileTag tagId='2' tagName='t2' />

<FileTag tagId='3' tagName='t3' />

<FileTagRel fileId='1' tagId='1' />

<FileTagRel fileId='1' tagId='2' />

<FileTagRel fileId='2' tagId='1' />

<FileTagRel fileId='2' tagId='3' />

<FileTagRel fileId='3' tagId='2' />

</dataset>

注意数据的顺序,否则会有约束违例,特别是外键约束

  1. 写基本的测试类

package mofile.share.dao;

import javax.sql.DataSource;

import mofile.common.utils.SpringBeanProxy;

import org.dbunit.DatabaseTestCase;

import org.dbunit.database.DatabaseConnection;

import org.dbunit.database.IDatabaseConnection;

import org.dbunit.dataset.IDataSet;

import org.dbunit.operation.DatabaseOperation;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**

* 使用dbunit

*

* @author weip

* @time 2006-3-9 13:42:32

*

*/

public abstract class BaseDaoTest extends DatabaseTestCase {

protected final static ApplicationContext ctx;

protected IDatabaseConnection conn = null;

protected IDataSet dataSet = null;

static {

// String pkg = ClassUtils.classPackageAsResourcePath(Constants.class);

String[] paths = { "classpath:applicationContext-share-database.xml",

"classpath:applicationContext-share-hibernate.xml",

"applicationContext-share-property.xml"/*

* ,

* "classpath:applicationContext-central-database.xml"

*/};

ctx = new ClassPathXmlApplicationContext(paths);

SpringBeanProxy.setApplicationContext(ctx);

}

public BaseDaoTest(String methodName) {

super(methodName);

}

/**

*

* @author weip

* @time 2006-3-9 13:46:45 (non-Javadoc)

* @see org.dbunit.DatabaseTestCase#getConnection()

*

*/

protected IDatabaseConnection getConnection() throws Exception {

DataSource ds = (DataSource) ctx.getBean("shareDataSource");

conn = new DatabaseConnection(ds.getConnection());

return conn;

}

/**

*

* @author weip

* @time 2006-3-9 13:52:27 (non-Javadoc)

* @see org.dbunit.DatabaseTestCase#getSetUpOperation()

*

*/

protected DatabaseOperation getSetUpOperation() throws Exception {

return DatabaseOperation.CLEAN_INSERT;

}

/**

*

* @author weip

* @time 2006-3-9 13:52:31 (non-Javadoc)

* @see org.dbunit.DatabaseTestCase#getTearDownOperation()

*

*/

protected DatabaseOperation getTearDownOperation() throws Exception {

//this.closeConnection(conn);

//conn=null;

return DatabaseOperation.NONE;

}

}

  1. 写具体的测试用例

package mofile.share.dao;

import java.io.FileInputStream;

import java.util.List;

import junit.framework.Test;

import junit.framework.TestSuite;

import mofile.share.domain.DefaultFile;

import mofile.share.domain.DefaultUser;

import mofile.share.domain.FileTag;

import mofile.share.domain.FileType;

import mofile.share.vo.FileForm;

import org.dbunit.dataset.IDataSet;

import org.dbunit.dataset.xml.FlatXmlDataSet;

import org.dbunit.operation.DatabaseOperation;

/**

*

* @author weip

* @time 2006-3-9 11:13:34

*

*/

public class FileDaoTest extends BaseDaoTest {

private FileDao fileDao;

protected void setUp() throws Exception {

super.setUp();

/*try {

DatabaseOperation.CLEAN_INSERT.execute(conn, dataSet);

} finally {

conn.close();

}*/

fileDao = (FileDao) ctx.getBean("fileDao");

}

protected void tearDown() throws Exception {

super.tearDown();

}

public FileDaoTest(String methodName) {

super(methodName);

}

public static Test suite() {

TestSuite suite = new TestSuite();

suite.addTest(new FileDaoTest("testQueryAllFiles"));

suite.addTest(new FileDaoTest("testQueryFilesByFileType"));

suite.addTest(new FileDaoTest("testAddFiles"));

suite.addTest(new FileDaoTest("testRemoveObject"));

return suite;

}

/**

*

*  @author weip

*  @time 22:53:34 2006-3-16

*  @see org.dbunit.DatabaseTestCase#getDataSet()

*/

protected IDataSet getDataSet() throws Exception {

dataSet = new FlatXmlDataSet(new FileInputStream("d:/Projects/Share/Mofile_share/htdocs/WEB-INF/classes/mofile/share/dao/testFileDB.xml"));

return dataSet;

}

/**

*

* @author weip

* @time 22:53:17 2006-3-16

* @throws Exception

*/

public void testAddFiles() throws Exception {

FileType fileType = new FileType();

fileType.setTypeId(new Integer(1));

FileTag fileTag = new FileTag();

fileTag.setTagName("dev3");

DefaultUser user = new DefaultUser();

// user.setLoginName("");

// user.setUserNo(new Long(1));

user.setUserId(new Long(1));

DefaultFile file = new DefaultFile();

file.setFileName("file001");

file.setFileSize(20);

file.setFileStatus(1);

file.setPickupCode("0001");

file.setStorageFileHome("xxx");

file.setStorageFileId(new Long(1));

file.setUser(user);

file.setFileType(fileType);

file.addTag(fileTag);

fileDao.saveObject(file);

DefaultFile fileafter=fileDao.getFileByStorageFileId("xxx",new Long(1));

assertNotNull(fileafter);

assertEquals("file001",fileafter.getFileName());

}

/**

*

* @author weip

* @time 2006-3-9 14:01:05

* @throws Exception

*/

public void testQueryAllFiles() throws Exception {

FileForm frm = new FileForm();

frm.setFileStatus(-1);

frm.setFileType(-1);

List list = fileDao.queryFile(frm);

assertEquals(3, list.size());

}

/**

*

* @author weip

* @time 22:47:01 2006-3-16

* @throws Exception

*/

public void testQueryFilesByFileType() throws Exception {

FileForm frm = new FileForm();

frm.setFileStatus(-1);

frm.setFileType(1);

List list = fileDao.queryFile(frm);

assertEquals(1, list.size());

}

/**

*

* @author weip

* @throws Exception

* @time 23:10:33 2006-3-16

*/

public void testRemoveObject() throws Exception {

fileDao.removeObject(DefaultFile.class, new Long(2));

FileForm frm = new FileForm();

frm.setFileStatus(-1);

frm.setFileType(-1);

List list = fileDao.queryFile(frm);

assertEquals(2, list.size());

}

}

对比以下以前写的测试用例

public class FileDaoImplTestCase extends BaseDaoTestCase {

private FileDao fileDao;

protected void setUp() throws Exception {

super.setUp();

fileDao = (FileDao) ctx.getBean("fileDao");

}

protected void tearDown() throws Exception {

super.tearDown();

}

public FileDaoImplTestCase(String methodName) {

super(methodName);

}

public static Test suite() {

TestSuite suite = new TestSuite();

// suite.addTest(new FileDaoImplTest("testRemoveObject"));

// suite.addTest(new UserDaoImplTest("testSaveObject"));

// suite.addTest(new FileDaoImplTestCase("testSaveObject"));

// suite.addTest(new FileDaoImplTestCase("testQueryFileByTag"));

//suite.addTest(new FileDaoImplTestCase("testQueryFile4Pagenation"));

suite.addTest(new FileDaoImplTestCase("testUpdateLastMonthPoints"));

return suite;

}

/*

* Test method for

* 'mofile.share.dao.impl.BaseHibernateDaoImpl.getObject(Class,

* Serializable)'

*/

public void testGetObject() {

}

/**

* 插入一条文件记录 ,注意插入记录需检查是否存在重复的filetag

*

* @author weip

* @time 16:42:20 2006-1-15

* @throws Exception

*

* Hibernate: insert into DefaultFile (fileName, fileSize, fileStatus,

* pickupCode, releaseDate, storageFileHome, storageFileId, userId, typeId)

* values (?, ?, ?, ?, ?, ?, ?, ?, ?) Hibernate: insert into FileTag

* (tagName) values (?) Hibernate: insert into FileTagRel (fileId, tagId)

* values (?, ?)

*

*/

public void testSaveObject() throws Exception {

FileType fileType = new FileType();

fileType.setTypeId(new Integer(1));

FileTag fileTag = new FileTag();

fileTag.setTagName("dev3");

DefaultUser user = new DefaultUser();

// user.setLoginName("");

// user.setUserNo(new Long(1));

user.setUserId(new Long(1));

DefaultFile file = new DefaultFile();

file.setFileName("file001");

file.setFileSize(20);

file.setFileStatus(1);

file.setPickupCode("0001");

file.setStorageFileHome("xxx");

file.setStorageFileId(new Long(1));

file.setUser(user);

file.setFileType(fileType);

file.addTag(fileTag);

fileDao.saveObject(file);

}

/**

*

* 删除一条文件记录

*

* @author weip

* @time 16:47:29 2006-1-15

*

* Hibernate: select defaultfil0_.fileId as fileId2_, defaultfil0_.fileName

* as fileName2_, defaultfil0_.fileSize as fileSize2_,

* defaultfil0_.fileStatus as fileStatus2_, defaultfil0_.pickupCode as

* pickupCode2_, defaultfil0_.releaseDate as releaseD6_2_,

* defaultfil0_.storageFileHome as storageF7_2_, defaultfil0_.storageFileId

* as storageF8_2_, defaultfil0_.userId as userId2_, defaultfil0_.typeId as

* typeId2_, defaultuse1_.userId as userId0_, defaultuse1_.loginName as

* loginName0_, defaultuse1_.userNo as userNo0_, filetype2_.typeId as

* typeId1_, filetype2_.typeName as typeName1_ from DefaultFile defaultfil0_

* left outer join UseInSharedSystem defaultuse1_ on

* defaultfil0_.userId=defaultuse1_.userId left outer join FileType

* filetype2_ on defaultfil0_.typeId=filetype2_.typeId where

* defaultfil0_.fileId=? Hibernate: select tagset0_.fileId as fileId__,

* tagset0_.tagId as tagId__, filetag1_.tagId as tagId0_, filetag1_.tagName

* as tagName0_ from FileTagRel tagset0_ inner join FileTag filetag1_ on

* tagset0_.tagId=filetag1_.tagId where tagset0_.fileId=? Hibernate: delete

* from FileTagRel where fileId=? Hibernate: delete from DefaultFile where

* fileId=?

*/

public void testRemoveObject() {

fileDao.removeObject(DefaultFile.class, new Long(2));

}

/**

* 测试按标签获取文件

*

* @author weip

* @throws Exception

* @time 2006-1-24 20:12:07

*/

public void testQueryFileByTag() throws Exception {

List list = fileDao.queryFileByTag(54, 0, 10);

assertNotNull(list);

DefaultFile file = null;

if (list.size() > 0)

file = (DefaultFile) list.get(0);

}

public void testQueryFile4Pagenation() throws Exception {

FileForm frm = new FileForm();

frm.setFileStatus(-1);

frm.setFileType(-1);

fileDao.queryFileSum(frm);

}

/**

* 测试 批量更新上月得分总数

*

* @author weip

* @throws Exception

* @time 2006-2-21 16:07:32

*/

public void testUpdateLastMonthPoints() throws Exception {

fileDao.updateLastMonthPoints();

assertTrue(true);

}

}

  • 总结

通过与以前的例子比较发现:使用dbunittestcase更自动化和可重复,以前写的testcase与数据库中的数据严重耦合,所以一般都不敢写断言,写了之后怕数据又发生变化,所以测试也是不可重复,并且也不是自动化,因为没有断言,你不得不测试完之后还得检查数据库。

当然dbunit也许并不是银弹,它在并发测试的时候得表现我没有实践过,也不敢妄下断言,而且是不是应该另外再建一个同样的数据专门测试dao还值得思考

我们在项目中为每个开发人员自建一个数据库解决并发问题,也许这个方案并非最佳,但实用

什么是dbunit以及为什么要使用它相关推荐

  1. Spring Boot 与DBunit 配合使用

    DBUnit 快速上手 Springboot 添加 DBunit 依赖 // https://mvnrepository.com/artifact/org.dbunit/dbunit testComp ...

  2. DBUnit使用介绍

    一.DbUnit设计理念 熟悉单元测试的开发人员都知道,在对数据库进行单元测试时候,通常采用的方案有运用模拟对象(mock objects)和stubs两种.通过隔离关联的数据库访问类,比如JDBC的 ...

  3. dbunit java_Java – 让DbUnit使用Hibernate事务

    我在尝试将Hibernate事务中的更改推送到数据库以使DbUnit在我的测试用例中正常工作时遇到问题.似乎DbUnit没有看到Hibernate所做的更改,因为它们还没有在事务结束时提交--而且我不 ...

  4. 使用DBUnit框架数据库插入特殊字符失败的查错经历

    本文记录的是使用DBUnit测试框架进行数据库数据插入时,插入特殊字符失败的查错经历.希望能对向我这样的小白同学们在遇到类似问题时,能够有一些启发. 背景: 在写跟数据库交互模块的单元测试,数据库表中 ...

  5. 使用dbunit和system-rules测试代码

    2019独角兽企业重金招聘Python工程师标准>>> 最近项目在搞batch的测试. 在进行ut测试时候,想将dbunit集成到测试中. 发现最新的2.5.3版本已经集成了从exc ...

  6. 单元测试之DBUnit的使用以及原理剖析

    前面介绍了不少写单元测试的内容,比方说Mockito和PowerMockito, JUnit 5,经常写单元测试的想必对这些框架都比较熟悉. 这篇博客主要介绍下数据库驱动测试框架–DbUnit(htt ...

  7. dbunit使用_摆脱困境:在DbUnit数据集中使用空值

    dbunit使用 如果我们正在为使用Spring Framework的应用程序编写集成测试,则可以通过使用Spring Test DbUnit将DbUnit与Spring测试框架集成. 但是, 这种集 ...

  8. dbunit测试dao_用于数据库测试的DBUnit,Spring和注释

    dbunit测试dao 如果您曾经尝试用Java编写数据库测试,则可能会遇到DBUnit . DBUnit允许您设置和拆除数据库,以便它包含可针对其编写测试的一致行. 通常,您可以通过编写一个简单的X ...

  9. dbunit使用_使用dbUnit,JSON,HSQLDB和JUnit规则进行数据库单元测试

    dbunit使用 在本周TDD课程的运行中,我认为编写一些夹具以简化dbUnit的使用将很有趣. 我最初的想法只是教dbUnit有关JSON的知识,但事实证明Lieven Doclo已经做到了. 因此 ...

  10. 摆脱困境:在DbUnit数据集中使用空值

    如果我们正在为使用Spring Framework的应用程序编写集成测试,则可以通过使用Spring Test DbUnit将DbUnit与Spring测试框架集成. 但是, 这种集成并非没有问题 . ...

最新文章

  1. SAP 电商云 Spartacus UI added-to-cart 的端到端测试源代码解析
  2. 从mysql的官网下载tar.gz结尾的mysql
  3. angularjs directive指令 link在渲染完成之后执行
  4. c 语言与试验系统,Turbo C/C++软件学习下载
  5. python组合数据类型实验报告_Python程序设计实验七:组合数据类型
  6. java 一元二次方程_Java类求解一元二次方程的根
  7. 抖音小程序开发所遇到的问题
  8. Google员工的工作环境
  9. css实现多行文本时显示省略号
  10. 线上展厅3d化宣传效果怎样 广州商迪
  11. 数通运营商方向常见面试问题(第五部分)
  12. Leetcode-数组-904
  13. html 按钮立体效果,纯CSS实现的立体按钮
  14. uiautomator_0
  15. Vue+Django使用Blob下载文件(xlsx为例)
  16. 区块链在能源领域落地?可自己发电卖给邻居
  17. 在ArrayList中根据自定义类的一个属性找某个对象
  18. 用PyTorch玩转Transformer英译中翻译
  19. 【第19章】操作系统安全保护(信息安全工程师) 软考笔记
  20. python计算器基础知识_计算机基础知识

热门文章

  1. 10中经济有好玩的约会方式
  2. 吃豆人html代码原理,如何用HTML做一个吃豆人?
  3. 白鹭引擎实现滚动视图效果
  4. 从 SXX32F103 移植到 MH32F103A参考文档
  5. Zygote进程启动过程源代码分析
  6. oracle11g的alert日志路径,oracle11g下alert文件位置
  7. unity官方资源包Standard Assets导入错误的解决方法
  8. 双轮驱动下的科大讯飞618:C端亮眼 六项第一 全线领跑!
  9. python 虚拟环境 django.db 报错_Django-笔记
  10. EOS系列 - 超级节点(BP)列表更新流程