dbunit实践指南

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情
  • 什么是dbunit以及为什么要使用它?

 

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的使用以及原理剖析 前面介绍了不少写单元测试的内容,比方说Mockito和PowerMockito, JUnit 5,经常写单元测试的想必对这些框架都比较熟悉。 这篇博客主要介绍下数据库驱动测试框架–DbUnit(http://dbunit.sourceforge.net/), 主要从DbUnit的设计原理和实际使用来展开,这里的使用我又分为三个部分: 基于spring-test-dbunit的使用 基于dbunit本身api的使用 在dbunit的基础上整合了公司自己的jdbc框架完成的工具类 DBUnit 设计原理 看 阅读详情

相关推荐

DbUnit使用简介

前言:本篇博客是翻译博文,本人是一名初学者,而且并非专业人员,完全出于自我学习的兴趣,以及交流的目的,有任何疑问或者发现错误请及时提醒,万分感谢。

fanxiaobin 5461

Dbunit简介

一、是什么?         DBunit 是一种扩展于JUnit的数据库驱动测试框架,它使数据库在测试过程之间处于一种已知状态,如果一个测试用例对数据库造成了破坏性影响,它可以帮助避免造成后面的测试失败或者给出错误结果。 二、怎么用?         基于DbUnit测试的主要接口是IDataSet。IDataSet代表一个或多个表的数据。 可以将数据库模式的全部内容表示为单个IDat

刘玉杰 点滴之笔 1557

dbunit实现原理及最佳实践

在使用dbunit写单元测试时,强烈建议先熟悉其底层的实现原理,否则可能导致测试数据库中的数据被清空的风险(尽管测试数据不如线上数据重要,但如果大量的测试数据被清空,导致测试环境不可用,数据恢复起来还是很头疼的!!)。参考博客1简单介绍了dbunit的实现原理: 第一步:事先把数据表里的数据以XML的格式导出来; 第二步:运行每一个测试之前先把当前数据表里的数据清空; 第三步:把XML里的数据再导进数据表; 第四步:数据表回到了单测前的状态。 由此可见,在单测的第二步中,会将数据表里的数据清空。如果你

Saintyyu的博客 2554

Springboot+DBunit单元测试,数据库隔离测试

关于DBunit 百度百科:dbunit是一个基于junit扩展的数据库测试框架。 简言之,dbunit是为了在单元测试中,通过备份数据库、导入测试数据、回滚恢复数据库的手段,在不污染数据库的前提下完成一系列单元测试工作。 DBunit关键知识点 IDataSet接口:用于操作表集合 ITable接口:用于操作表数据集合 DatabaseOperation类:对表数据执行一系列操作,比如刷新、删除...

Oumuv的博客 4935

DBUnit实践

DBUnit实践:[url]http://www.iteye.com/topic/81633[/url]

竹林闲人 124

DBunit入门

<br /> 使用DBTestCase子类设置数据库<br />第1步:创建你的数据集文件<br /><br />你的测试需要一些数据来辅助。也就是说你必须创建一个数据集。在大多数情况下你会使用XML数据集。你可以手动从头创建一个flat XML数据集或从你的数据库中导出一些数据。第2步:扩展类的DBTestCase<br />现在您需要创建一个测试类。最简单的使用DBUnit的方法是是你的测试类继承DBTestCase。DBTestCase扩展了JUnit TestCase类。一个getDataSet()

BoBo的代码世界 3522

DbUnit实践:Spring Test Dbunit,H2数据库

概述        Dbunit是一个基于JUnit的数据库集成测试框架。DBUnit 的设计理念就是在测试之前,给对象数据库植入我们需要的准备数据,最后,在测试完毕后,回溯到测试前的状态;它使数据库在测试过程之间处于一种已知状态,如果一个测试用例对数据库造成了破坏性影响,它可以帮助避免造成后面的测试失败或者给出错误结果。        Spring Test DbUnit提供了Spr

and1kaney的专栏 1万+

DBUnit入门

相信做过单元测试的人都会对JUnit非常的熟悉了,今天要介绍的DbUnit(http://dbunit.sourceforge.net/)则是专 门针对数据库测试的对JUnit的一个扩展,它可以将测试对象数据库置于一个测试轮回之间的状态。鉴于目前国内介绍DbUnit的系统教程比较少见,本文 将分从理论和实例两个方面带你领略DbUnit的精彩世界。 DbUnit设计理念 熟悉单元测试的开发人员都知...

weixin_33972649的博客 2111

Dbunit最佳实践

原文:http://dbunit.sourceforge.net/bestpractices.htmlBest Practices Use one database instance per developer Good setup dont need cleanup! Use multiple small datasets Pe

pwlazy的专栏 2730

Spring Test DBUnit 入门指南

Spring Test DBUnit 入门指南 Spring Test DBUnit 是一个用于集成测试的开源库,它结合了 Spring 测试框架和 DBUnit 的强大功能,使得在进行数据库相关的单元和集成测试时更加便捷高效。通过本指南,您将学习到如何快速地将其应用于您的项目中,掌握最佳实践,并了解其在技术生态中的定位。 项目介绍 Spring Test DBUnit 提供了一组方便的 API,...

gitblog_01051的博客 861

dbunit使用

1.dbunit从名字上可以看出,是对有关数据库操作的测试。官网:www.dbunit.org从官网下载dbunit相关的jar包,dbunit还依赖于http://www.slf4j.org和commons-logging.jar,所以也需要下载slf4j,使用它的slf4j-api-1.5.3.jar和slf4j-jcl-1.5.3.jar。 dbunit的原理是:它会把数据库表里的

luoyuchuan的专栏 934

什么是dbunit以及为什么要使用它

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

张龙(风中叶)的专栏 4894

DbUnit 简介和使用 (puts your database into a known state)

DbUnit简介1.      引言在写持久层测试用例的时候,由于我们的测试是要依赖于外部的数据库,数据库里面的数据影响我们测试,往往是要在数据库中去查询得到数据表数据的状态,然后才能在TestCase里面写断言。数据表的状态又是可变的,所以经常要在此来回切换。可能产生如下场景:1)        

abing37的专栏 3354

DBUnit

DBUnit官方网站:www.dbunit.org About DbUnit DbUnit is a JUnit extension (also usable with Ant) targeted at database-driven projects that, among other things, puts your database into a known state between ...

天行者-阿纳金的博客 351

DbUnit入门实战

DbUnit入门实战--------By 白痴的青空 http://idiotsky.blog.ccidnet.com Mail wengyx1231@sina.comMsn wengyx@hotmail.com相信做过单元测试的人都会对JUnit非常的熟悉了,今天要介绍的DbUnit(http://dbunit.sourceforge.net/)则是专门针对数据库测试的对JUnit的一个扩展,它

yuezu技术专栏 1898
上一篇: org.apache.commons.logging的用法(下)
下一篇: EasyMock实践指南
pwlazy
博客等级 码龄24年 327粉丝 200原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值