- 浏览: 94626 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
shanpao1234560:
<div class="quote_title ...
Java 7 Fork/Join 并行计算框架概览 -
julydave:
文章中的例子显然是有问题的,没有对forkjoin正确使用…… ...
Java 7 Fork/Join 并行计算框架概览 -
wangyu1221:
这几天做的事情和lz做的事情基本相同,碰到的一个事务锁问题被l ...
在Spring中结合Dbunit对Dao进行集成单元测试 -
墨子宇:
因为其在下载前就弹出对话框让用户选择下载文件的存放路径,所以无 ...
Flex文件上传下载 -
duzc2:
Executor框架 的链接:http://mshijie.i ...
Java 7 Fork/Join 并行计算框架概览
package com.test.dbunit.dao; import javax.sql.DataSource; import org.dbunit.Assertion; import org.dbunit.database.DatabaseConnection; import org.dbunit.database.IDatabaseConnection; import org.dbunit.database.QueryDataSet; import org.dbunit.dataset.IDataSet; import org.dbunit.dataset.xml.FlatXmlDataSet; import org.dbunit.operation.DatabaseOperation; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.datasource.DataSourceUtils; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; import org.springframework.test.context.transaction.TransactionConfiguration; import com.test.dbunit.entity.User; @ContextConfiguration(locations = { "classpath:testApplicationContext.xml" }) @TransactionConfiguration(defaultRollback = true) public class UserDaoTest extends AbstractTransactionalJUnit4SpringContextTests { @Autowired private UserDao userDao; @Autowired private DataSource dataSource; private IDatabaseConnection conn; @Before public void initDbunit() throws Exception { conn = new DatabaseConnection(DataSourceUtils.getConnection(dataSource)); } @Test public void saveUser() throws Exception { User user = new User(); user.setNick("user001"); user.setPassword("password001"); userDao.save(user); QueryDataSet actual = new QueryDataSet(conn); actual.addTable("user", "select * from user where user.nick = 'user001'"); IDataSet expected = new FlatXmlDataSet(new ClassPathResource( "com/taobao/dbunit/dao/user001.xml").getFile()); Assertion.assertEquals(expected, actual); } @Test public void updateUser() throws Exception { IDataSet origen = new FlatXmlDataSet(new ClassPathResource( "com/taobao/dbunit/dao/user001.xml").getFile()); DatabaseOperation.INSERT.execute(conn, origen); User user = new User(); user.setNick("user001"); user.setPassword("password002"); userDao.update(user); QueryDataSet actual = new QueryDataSet(conn); actual.addTable("user", "select * from user where user.nick = 'user001'"); IDataSet expected = new FlatXmlDataSet(new ClassPathResource( "com/taobao/dbunit/dao/user001_updated.xml").getFile()); Assertion.assertEquals(expected, actual); } @Test public void removeUser() throws Exception { IDataSet origen = new FlatXmlDataSet(new ClassPathResource( "com/taobao/dbunit/dao/user001.xml").getFile()); DatabaseOperation.INSERT.execute(conn, origen); userDao.remove("user001"); QueryDataSet actual = new QueryDataSet(conn); actual.addTable("user", "select * from user where nick = 'user001'"); Assert.assertEquals(0, actual.getTable("user").getRowCount()); } @Test public void findUser() throws Exception { IDataSet data = new FlatXmlDataSet(new ClassPathResource( "com/taobao/dbunit/dao/user001.xml").getFile()); DatabaseOperation.INSERT.execute(conn, data); User user = userDao.getUserByNick("user001"); Assert.assertEquals("password001", user.getPassword()); } }
对Dao进行单元测试,一般有两种思路。一是Mock,对使用的底层API进行Mock,比如Hibernate和JDBC接口,判断接口有没有正确调用,另一种是实际访问数据库,判断数据库有没有正确读写。更多的情况下,我更倾向于后者,因为在使用ORM工具或者jdbcTemplate的情况下,dao一般只有简单的几行代码,没有复杂的逻辑,Mock测试一般没有什么意义,我们更关心的是,Hibernate mapping是否正确,ibatis sql是否正确等,所以实际读写数据库才能真正判断一个dao是否正确,这也是我们关心的测试内容。
好的单元测试应该是原子性的,独立的,不应依赖其他测试和上下文,但是要测试数据读写是否正确,就必须涉及初始数据的加载,数据修改的还原等操作。对于初始数据的加载,手动输入很麻烦,一个解决方案就是使用Dbunit,从Xml文件甚至Excel中加载初始数据到数据库,是数据库的值达到一个已知状态。同时还可以使用Dbunit,对数据库的结果状态进行判断,保证和期望的一致。数据修改的还原,可以依赖Spring TransactionalTests,在测试完成后回滚数据库。
Dbunit还可以对数据的现有数据进行备份,还原,清空现有数据,一个好的测试实践是每一个开发人员一个测试数据库,进而对数据库的数据状态有更好的控制,但现实可能会是共享同一个测试库,所以这种情况下,测试的编写必须多做一些考虑。
待测试的类:
package com.test.dbunit.dao.impl; import java.sql.ResultSet; import java.sql.SQLException; import org.springframework.jdbc.core.RowMapper; import com.test.dbunit.dao.UserDao; import com.test.dbunit.entity.User; public class DefaultUserDao extends BaseDao implements UserDao { private static String QUERY_BY_NICK = "select * from user where user.nick = ?"; private static String REMOVE_USER = "delete from user where user.nick = ?"; private static String INSERT_USER = "insert into user(nick,password) values(?, ?)"; private static String UPDATE_USER = "update user set user.password = ? where user.nick = ?"; @Override public User getUserByNick(String nick) { return (User) getJdbcTemplate().queryForObject(QUERY_BY_NICK,new Object[]{nick}, new RowMapper(){ @Override public Object mapRow(ResultSet rs, int index) throws SQLException { User user = new User(); user.setNick(rs.getString("nick")); user.setPassword(rs.getString("password")); return user; } }); } @Override public void remove(String nick) { getJdbcTemplate().update(REMOVE_USER, new Object[]{nick}); } @Override public void save(User user) { getJdbcTemplate().update(INSERT_USER, new Object[]{user.getNick(), user.getPassword()}); } @Override public void update(User user) { getJdbcTemplate().update(UPDATE_USER, new Object[]{user.getPassword(), user.getNick()}); } }
单元测试:
需要注意的地方就是,DataSourceUtils.getConnection(datasource) , 通过这种方式获得数据库连接初始化Dbunit,能够保证Dbunit使用的数据连接和当前事务的数据库连接相同,保证能够在参与到事务中。Spring的TransactionManager会在开始事务时把当前连接保存到ThreadLocal中,DataSourceUtils.getConnection方法,首先从ThreadLocal中获取连接。
user001.xml
<?xml version="1.0" encoding="UTF-8"?> <dataset> <user nick="user001" password="password001" /> </dataset>
使用dbunit,可以通过xml文件定义数据集,也可以使用其他方式定义,比如Excel,编程方式。
Dbunit的主要构件
IDatabaseConnection
数据库链接。实现类有DatabaseConnection 和DatabaseDataSourceConnection ,执行数据库操作时需要一个连接。
IDataSet
数据集,数据集可以从Xml文件Excel等外部文件获取,也可以从数据库查询,或者编程方式构件,数据集可以作为初始数据插入到数据库,也可以作为断言的依据。另外还有IDatatable等辅助类。
比如在updateUser测试中,使用了QueryDataSet,从数据库中构建一个Dataset,再通过FlatXmlDataSet从Xml文件中构建一个Dataset,断言这两个Dataset相同。
QueryDataSet actual = new QueryDataSet(conn); actual.addTable("user", "select * from user where user.nick = 'user001'"); IDataSet expected = new FlatXmlDataSet(new ClassPathResource( "com/taobao/dbunit/dao/user001_updated.xml").getFile()); Assertion.assertEquals(expected, actual);
DatabaseOperation
通过定义的静态字段可以获取一组代表一个数据操作的子类对象,比如DatabaseOperation .INSERT,返回 InsertOperation,通过执行execute方法把数据集插入到数据库。例如:
IDataSet origen = new FlatXmlDataSet(new ClassPathResource( "com/taobao/dbunit/dao/user001.xml").getFile()); DatabaseOperation.INSERT.execute(conn, origen);
从Xml文件中构建DataSet,使用Insert插入到数据库,初始化测试数据。
Assertion
唯一的方法,assertEqual,断言两个数据集或数据表相同。
更多关于Dbunit的组件的介绍:http://www.dbunit.org/components.html
PS:使用Oracle的时候,初始化DatabaseConnection需要传入scheme。new DatabaseConnection(conn,SCHEMA_NAME ) ,SCHMEA_NAME需要大写。
附件提供所有代码下载
一个DAO测试基类
package com.taobao.dbunit.dao; import java.sql.SQLException; import javax.sql.DataSource; import org.dbunit.Assertion; import org.dbunit.database.DatabaseConnection; import org.dbunit.database.IDatabaseConnection; import org.dbunit.dataset.DataSetException; import org.dbunit.dataset.DefaultDataSet; import org.dbunit.dataset.DefaultTable; import org.dbunit.dataset.IDataSet; import org.dbunit.dataset.xml.FlatXmlDataSet; import org.dbunit.operation.DatabaseOperation; import org.junit.Assert; import org.junit.Before; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.datasource.DataSourceUtils; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; import org.springframework.test.context.transaction.TransactionConfiguration; @ContextConfiguration(locations = { "classpath:testApplicationContext.xml" }) @TransactionConfiguration(defaultRollback = true) public class BaseDaoTest extends AbstractTransactionalJUnit4SpringContextTests { @Autowired private DataSource dataSource; private IDatabaseConnection conn; @Before public void initDbunit() throws Exception { conn = new DatabaseConnection(DataSourceUtils.getConnection(dataSource)); } /** * 清空file中包含的表中的数据,并插入file中指定的数据 * * @param file * @throws Exception */ protected void setUpDataSet(String file) throws Exception { IDataSet dataset = new FlatXmlDataSet(new ClassPathResource(file) .getFile()); DatabaseOperation.CLEAN_INSERT.execute(conn, dataset); } /** * 验证file中包含的表中的数据和数据库中的相应表的数据是否一致 * * @param file * @throws Exception */ protected void verifyDataSet(String file) throws Exception { IDataSet expected = new FlatXmlDataSet(new ClassPathResource(file) .getFile()); IDataSet dataset = conn.createDataSet(); for (String tableName : expected.getTableNames()) { Assertion.assertEquals(expected.getTable(tableName), dataset .getTable(tableName)); } } /** * 清空指定的表中的数据 * * @param tableName * @throws Exception */ protected void clearTable(String tableName) throws Exception { DefaultDataSet dataset = new DefaultDataSet(); dataset.addTable(new DefaultTable(tableName)); DatabaseOperation.DELETE_ALL.execute(conn, dataset); } /** * 验证指定的表为空 * * @param tableName * @throws DataSetException * @throws SQLException */ protected void verifyEmpty(String tableName) throws DataSetException, SQLException { Assert.assertEquals(0, conn.createDataSet().getTable(tableName) .getRowCount()); } }
使用:
@Test public void updateUser() throws Exception { setUpDataSet("com/taobao/dbunit/dao/user001.xml"); User user = new User(); user.setNick("user001"); user.setPassword("password002"); userDao.update(user); verifyDataSet("com/taobao/dbunit/dao/user001_updated.xml"); }
- dbunit.rar (14.2 KB)
- 下载次数: 471
评论
这个确实是一个问题。测试数据构造还是很麻烦的。批量数据生成的时候,我会考虑用数据生成工具,比如EMS Data Generator,然后写个脚本导入到Xml或Excel供dbunit使用。数据维护上,只能依靠团队内部的规范了。你们有没有什么好的方案?
把表关联都断掉。
用到什么数据插什么数据。
硬sql insert进去
最主要的是不测试SERVICE
只测试DAO代码量就会少很多
这个确实是一个问题。测试数据构造还是很麻烦的。批量数据生成的时候,我会考虑用数据生成工具,比如EMS Data Generator,然后写个脚本导入到Xml或Excel供dbunit使用。数据维护上,只能依靠团队内部的规范了。你们有没有什么好的方案?
是一个内存数据库,用它来开发,不用引入DBUnit就可以测试DAO了;
希望会对你有帮助;
使用H2或者HSQL有个问题就是,sql语法的差异问题。用Hibernate还好,可以我们更多的使用ibatis,这个Sql差异问题就麻烦了,尤其是用Oracle的时候。还得为HSQL单独弄一份DDL。实际用起来很多问题啊。Hibernate的话,推荐用这个方法。
是一个内存数据库,用它来开发,不用引入DBUnit就可以测试DAO了;
希望会对你有帮助;
import java.io.File; import java.io.FileWriter; import java.io.Writer; import javax.sql.DataSource; import org.apache.commons.io.FileUtils; import org.dbunit.Assertion; import org.dbunit.database.DatabaseConnection; import org.dbunit.database.IDatabaseConnection; import org.dbunit.database.QueryDataSet; import org.dbunit.dataset.IDataSet; import org.dbunit.dataset.xml.XmlDataSet; import org.dbunit.dataset.xml.XmlDataSetWriter; import org.dbunit.operation.DatabaseOperation; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.datasource.DataSourceUtils; public class DbUnitUtils extends SpringTxTestCase { private IDatabaseConnection conn; public static final String SCHEMA_NAME = "test1"; @Autowired private DataSource dataSource; @Before public void initDbunit() throws Exception { conn = new DatabaseConnection(DataSourceUtils.getConnection(dataSource), SCHEMA_NAME); } // @Test public void exportData() { exportTable("/home/test1/temp/depart.xml", "depart"); } @Test public void importData() { String insertFile = "dbunit/depart/insert.xml"; importTable(insertFile); verifyDataSet(insertFile); } /** * 验证file中包含的表中的数据和数据库中的相应表的数据是否一致 * * @param xmlFileClassPath * @throws Exception */ protected void verifyDataSet(String xmlFileClassPath) { try { IDataSet expected = new XmlDataSet(new ClassPathResource(xmlFileClassPath).getInputStream()); IDataSet dataset = conn.createDataSet(); for (String tableName : expected.getTableNames()) { Assertion.assertEquals(expected.getTable(tableName), dataset.getTable(tableName)); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 导出数据到指定文件 * * @param file * @param connection * @throws Exception */ private void exportTable(String file, String tableName) { QueryDataSet dataSet = new QueryDataSet(conn); try { File outputFile = new File(file); FileUtils.touch(outputFile); dataSet.addTable(tableName); Writer writer = new FileWriter(file); XmlDataSetWriter w = new XmlDataSetWriter(writer); w.setIncludeColumnComments(true); w.write(dataSet); writer.flush(); writer.close(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 导入数据到表 * * @param xmlFileClassPath * @param tableName */ public void importTable(String xmlFileClassPath) { try { IDataSet dataSet = new XmlDataSet(new ClassPathResource(xmlFileClassPath).getInputStream()); DatabaseOperation.INSERT.execute(conn, dataSet); flush(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } }
发表评论
-
使用Berkeley DB构建持久化队列
2010-04-13 20:25 4967Berkeley DB简介 Berkeley DB(以下简称 ... -
《Clean Code》总结 异常
2010-03-14 18:13 13931.使用异常而不是错误码 如果使用错误码,调用者,必须在方法调 ... -
《Clean Code》总结 方法
2010-03-14 18:08 13841.方法要可能的短。最好控制在几行以内。 例如: public ... -
《Clean Code》总结 有意义的命名
2010-03-12 11:57 1578编写代码时,尽量使用有意义的名称命名类、方法、变量等 1.使 ... -
Getting Started with Lucene
2010-02-22 14:27 1163Lucene是一个高性能的, ... -
使用Unitils测试DAO
2009-11-24 19:30 4407上个月在博客中,讲了怎么使用dbunit帮助测试dao。但是在 ... -
[转]TDD全攻略
2009-11-20 20:17 961原文链接:http://www.blogjava.net/br ... -
代码备份build.xml
2009-07-30 10:29 1401<?xml version="1.0" ... -
@Override的在1.5和1.6中的不同含义
2009-07-29 18:45 3459今天在用ant编译的时候遇到一个问题,老是提示 @Overri ... -
集成struts2 spring hibernate,使用注解
2009-04-01 20:21 4042集成struts,spring,hibernate时,对于初学 ...
相关推荐
NULL 博文链接:https://xiangxingchina.iteye.com/blog/1752521
一个很好的DBUnit的例子 博文链接:https://virgoooos.iteye.com/blog/186859
unitils整合dbunit利用excel进行单元测试 包含mock以及整合spring进行测试
NULL 博文链接:https://xiongzhenhui.iteye.com/blog/802984
在最近的一个项目中,我尝试使用用DBUnit对Spring+iBatis的架构进行测试,下面记录了DBUnit的使用过程和遇到的一些问题。首先,我们建立一个测试环境(基于Maven2和Oracle数据库*)。数据表名Account。先建立一个...
用DbUnit进行SqlMap单元测试 摘自:http://www.uml.org.cn/Test/200811278.asp
下面小编就为大家带来一篇对dbunit进行mybatis DAO层Excel单元测试(必看篇)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
采用 Java 编写的数据库系统单元测试程序。
Junit,dbunit单元测试jar包
DbUnit是一款开源的数据库功能测试框架,使用它可以对数据库的基本操作进行白盒单元测试,对输入输出进行校验,从而保证数据的有效性。DbUnit使用XML文件提供测试数据,为测试人员增加了测试难度,降低了单元测试效率。...
单元测试入门学习,和dbunit结合开发
1. 测试环境的搭建(DBunit+HSQLDB) 1 1.1. DBunit的简介 1 1.1.1. DBunit简单介绍和原理 1 1.1.2. DBunit的三大核心组件 1 1.1.3. DBunit的安装使用 2 1.2. HSQLDB简介 3 1.2.2. 什么是HSQLDB 3 1.2.3. HSQLDB安装...
自述文件这个 repo 是我尝试使用 Spring Test DBUnit 实现的示例。 基本上我在 src/main/java/com/springtests/model 中有三个实体节目表演者每个都有自己的 ID 字段,并与具有三列的连接表 (prog_performer) 建立多...
dbunit2.2完全包 数据库单元测试
NULL 博文链接:https://yugouai.iteye.com/blog/1876827
DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类DBUNIT 基类...
2.3.4 在Spring中装配DAO 2.4 业务层 2.4.1 UserService 2.4.2 在Spring中装配Service 2.4.3 单元测试 2.5 展现层 2.5.1 配置Spring MVC框架 2.5.2 处理登录请求 2.5.3 JSP视图页面 2.6 运行Web应用 2.7 小结 第2篇...