1.1.1 数据库测试
数据库层的单元测试对构建企业应用来说是比较有价值的,但是由于过于复杂我们不得不放弃他。Unitils降低了数据库测试的复杂度,让数据库测试简单而又容易维护,下面的章节描述DatabaseModule andDbUnitModule 怎么对你的数据库测试提供支持。
1.1.1.1
使用Dbunit维护测试数据
数据库测试应该使用单元测试数据库,这样你可以完全的精细的控制你使用到的测试数据。DbUnitModule 是基于DBunit构建的,可以提供对测试数据集的支持。
1.1.1.1.1 装载测试数据集
让我们看一个例子,UserDao有一个简单的方法findByName,用来通过用户的first 和last
name来取回用户,常用的单元测试如下:
@DataSet
public class UserDAOTest extends UnitilsJUnit4 {
@Test
public void testFindByName() {
User result = userDao.findByName("doe", "john");
assertPropertyLenientEquals("userName", "jdoe", result);
}
@Test
public void testFindByMinimalAge() {
List<User> result = userDao.findByMinimalAge(18);
assertPropertyLenientEquals("firstName", Arrays.asList("jack"), result);
}
}
@DataSet注解是通知Unitils查找测试需要加载的Dbunit数据文件。如果没有指定文件名,Unitils会在当前文件夹自动查找和测试类文件名相同的数据集文件如:className.xml.
数据集文件应该使用Dbunit的 FlatXMLDataSet 格式,并且应该包含所有测测试数据。所有表的内容首先被清空,然后所有的测试数据被插入。不在数据文件中的表,是不会被清空内容的。你如果需要清空特定的表你可以在文件中加入一个表的空标签,如:<MY_TABLE />,对于插入null值,你也可以使用类似的方法。
对UserDaoTest你需要建立一个数据集文件名称为:UserDaoTest.xml 并且把它放到UserDaoTest 类文件所在的目录。
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<usergroup name="admin" />
<user userName="jdoe" name="doe" firstname="john" userGroup="admin" />
<usergroup name="sales" />
<user userName="smith" name="smith" userGroup="sales" />
</dataset>
这会清空user表和usergroup表,并且插入新的记录,用户名为smith的用户的first name会被设置null值。
支持testFindByMinimalAge()方法需要特殊的数据集而不是类级别的数据集。那么你需要建立一个文件:UserDAOTest.testFindByMinimalAge.xml 并且放在和测试类相同的文件夹即可
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<user userName="jack" age="18" />
<user userName="jim" age="17" />
</dataset>
你可以用这个数据集文件通过给这个方法上标注@DataSet注解,来覆盖类的数据集文件。
public class UserDAOTest extends UnitilsJUnit4 {
@Test
@DataSet("UserDAOTest.testFindByMinimalAge.xml")
public void testFindByMinimalAge() {
List<User> result = userDao.findByMinimalAge(18);
assertPropertyLenientEquals("firstName", Arrays.asList("jack"), result);
}
}
方法级别的数据集文件不应该被过度使用,因为过多的数据文件意味这更多的维护工作,你应该尽量减少数据在类级别的数据集,多数情况下比较小的数据集就可以给多个单元测试公用。但是如果公用数据导致了数据量的增大和杂乱,那么用方法级别的数据集,或者细分单元测试类,每个类用自己的数据集。
给一个类或者其父类通过@DataSet设置的数据集对类里的每个测试方法都有效。如果一个数据集只被几个测试方法使用,那么你最好不要把他们放在类级别的注解里,而应该在相应的测试方法上加上注解。如果你的数据集文件没有像我们前面描述的那样命名,你也可以自己命名,当然只需要在@dataset注解中标明即可,你也可以使用多个数据集文件,如下示例:
@DataSet({"UserDAOTest_general.xml", "ConfigSettings.xml"})
public class UserDAOTest extends UnitilsJUnit4 {
@Test
public void testFindByName() {
User result = userDao.findByName("doe", "john");
assertPropertyLenientEquals("userName", "jdoe", result);
}
@Test
@DataSet("UserDAOTest_ages.xml")
public void testFindByMinimalAge() {
List<User> result = userDao.findByMinimalAge(18);
assertPropertyLenientEquals("firstName", Arrays.asList("jack"), result);
}
}
1.1.1.1.2 数据集加载策略设置
默认情况下,数据集加载是,采用先清除后插入的策略。那就意味着所有涉及的表中数据会被删除,然后再插入测试数据。这个动作时可以被设置的,你可以通过如下配置来编辑DbUnitModule.DataSet.loadStrategy.default,
如果我们在Unitils.properties文件中这么修改:
DbUnitModule.DataSet.loadStrategy.default=org.unitils.dbunit.datasetloadstrategy.InsertLoadStrategy
这样设置的话,就不会先删除现有数据了,而只是插入数据。
加载策略也可以对特定的测试类来设置,需要在@DataSet注解中这么标注:
@DataSet(loadStrategy = InsertLoadStrategy.class)
如果你熟悉Dbunit,配置加载策略类似于使用不同的数据库,下面是默认支持的加载策略:
-
CleanInsertLoadStrategy:
先清除后插入策略
-
InsertLoadStrategy:
仅仅插入数据
-
RefreshLoadStrategy: 刷新数据库内容,如果数据库已经有了会使用数据集的数据更新它,如果数据库没有,就会把数据集的输入插入。数据库里有但是数据集中没有的数据不会受到影响。
-
UpdateLoadStrategy: 数据库存在的数据会被更新,但是如果数据集中有但是数据库中没有的话不会有数据变动。
1.1.1.1.3 配置数据集工厂
Unitils的数据集文件使用multischema xml 格式,这是DbUnits FlatXmlDataSet 格式的一个扩展版本。数据集工厂来管理文件格式的配置和文件扩展。
尽管Unitils目前只支持一种数据集格式,但是通过自定义的数据集工厂的实现是可以支持不同的文件格式的。
你可以通过Unitils.propertis文件的DbUnitModule.DataSet.factory.default 属性配置或者在@DataSet注解中标明。例如你可以建立一个DbUnit的XlsDataSet通过实现DataSetFactory来使用Excel文件作为数据集文件。
1.1.1.1.4 验证测试结果
在测试运行后,有时候使用数据集的数据来对比数据库的内容是比较有用的。例如当你想检查大量数据更新或者存储过程执行的结果。
下面的例子测试一个方法,这个方法禁用所有一整年没有活动的用户的帐号:
public class UserDAOTest extends UnitilsJUnit4 {
@Test @ExpectedDataSet
public void testInactivateOldAccounts() {
userDao.inactivateOldAccounts();
}
}
注意我们在这个方法上增加了@ExpectedDataSet 注解。这会让Unitils寻找数据集文件UserDAOTest.testInactivateOldAccounts-result.xml并且比较数据库内容和数据集的数据。
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<user userName="jack" active="true" />
<user userName="jim" active="false" />
</dataset>
对这个数据集,Unitils会检查是否有两个不同的用户记录在用户表。其他的记录或其他表不会涉及。
使用@DataSet注解,文件名是可以被指定的,如果名字没有指定,那么会查找类似格式文件名的文件: className.methodName-result.xml
结果数据集应该尽量小。数据多意味着维护量变大。还有,最好尽量执行相同的检查在测试代码里。
1.1.1.1.5 多数据库测试
一些应用使用了多个数据库。为了实现这个功能,Unitils的数据集XML文件中可以对多数据库进行支持。下面的例子展现了怎么为两个数据库的数据表装载数据。
<?xml version='1.0' encoding='UTF-8'?>
<dataset xmlns="SCHEMA_A" xmlns:b="SCHEMA_B">
<user id="1" userName="jack" />
<b:role id="1" roleName="admin" />
</dataset>
这个例子我们定义了两个方案,A和B,schema-A和默认的XML命名空间关联,schema B关联命名空间b.如果一个表的描述中有前缀指明哪个命名空间,那么就会用指定的,否则默认schema A。
如果没有默认的命名空间,那么系统会默认在database.schemaNames属性中第一个schema。所以系统是支持你如下定义的。
database.schemaNames=SCHEMA_A, SCHEMA_B
这样系统默认schema-A 为默认的schema,那么你就可以不用再声明默认的schema了。
<?xml version='1.0' encoding='UTF-8'?>
<dataset xmlns:b="SCHEMA_B">
<user id="1" userName="jack" />
<b:role id="1" roleName="admin" />
</dataset>
1.1.1.1.6 连接测试数据库
上面的例子我们没有提到一件重要的事情,连接测试数据库的数据源在哪里,并且怎么让我们的UseDao使用这个数据源?
当你的第一个数据库测试在测试组件中运行的时候,Unitils会使用配置的属性建立一个数据源实例,去连接测试数据库。后面的数据库测试会仍会使用这个数据源,连接的详细属性描述如下:
database.driverClassName=oracle.jdbc.driver.OracleDriver
database.url=jdbc:oracle:thin:@yourmachine:1521:YOUR_DB
database.userName=john
database.password=secret
database.schemaNames=test_john
通常驱动和url配置放在Unitils.properties文件里作为项目共用,用户密码可以放在Unitils-local.properties作为每个开发者自己的设置。这样可以让每个开发者使用自己的测试数据,防止互相干扰。
当一个测试开始执行的时候,数据源示例会被注入到测试实例中,如果一个属性或者setter方法用注解@TestDataSource指定了,那么系统会使用你指定的数据源。你仍需要提供一些项目特定的代码来让你的代码使用这个数据源。通常这些配置在项目父类中被执行一次,简单的示例如下:
public abstract class BaseDAOTest extends UnitilsJUnit4 {
@TestDataSource
private DataSource dataSource;
@Before
public void initializeDao() {
BaseDAO dao = getDaoUnderTest();
dao.setDataSource(dataSource);
}
protected abstract BaseDAO getDaoUnderTest();
}
The above example uses
annotations to get a reference to the datasource. Another way of making your
code use the Unitils DataSource is by callingDatabaseUnitils.getDataSource().
上面的例子使用注解获取一个指定的数据源。另一个使用UnitilsDataSource的方法是使用DatabaseUnitils.getDataSource().
1.1.1.1.7 事务处理
很多情况下我们我们要以事务的方式存取数据,例如:
-
数据库动作仅在事务执行的时候存在,如使用 SELECT
FOR UPDATE 或者提交的时候有触发器行为
-
许多项目运行测试前,需要先准备一些general-purpose数据,每个测试前数据会有插入或修改。为了确保数据库在每个测试前都有一个已知的明确的状态,那么在每个测试前事务要开始,执行完以后事务需要回滚。
-
当我们使用hibernate或者JPA,他可能要求你使用事务为每个测试,来保证系统的正常运行。
By default every test is
executed in a transaction, which is committed at the end of the test.
默认状况下每个以事务方式执行的测试,完成后数据会被提交。
默认的动作可以通过配置来修改,如:
DatabaseModule.Transactional.value.default=disabled
可选的值还有: commit, rollback and disabled.
事务行为可以在测试类中被修改,会用到 @Transactional.注解如:
@Transactional(TransactionMode.ROLLBACK)
public class UserDaoTest extends UnitilsJUnit4 {
这样这个测试类的每个测试执行后数据将回滚。@Transactional 注解是可以被继承的。如果有必要你可以在你测试类的父类中使用。
其实,Unitils依赖Spring的事务管理,但这不意味着你必须使用Spring在你的应用代码里。实际上对用户来说那是透明的。
如果你继承了Unitils和Spring,并且你已经配置了bean的类型PlatformTransactionManager 在Spring配置里。Unitils会使用这个事务管理器。
分享到:
相关推荐
unitils-3.3-with-dependencies.zip
Unitils-core-3.3的jar包
bytesize.zip,用于格式化和解析数据大小的简单Java实用程序。用于格式化和解析数据大小的Java实用程序。
Unitils 测试框架目的是让单元测试变得更加容易和可...支持数据库测试,支持利用Mock 对象 进行测试并提供与Spring 和Hibernate 相集成。Unitils 设计成以一种高度可配置和松散耦 合的方式来添加这些服务到单元测试中
NULL 博文链接:https://mshijie.iteye.com/blog/524744
Unitils 模块 - 启动 Selenium Web 驱动程序以测试 Web 应用程序的简单方法。
Unitils构建在DBUnit与EasyMock项目之上并与JUnit和TestNG相结合,支持数据库测试,支持利用mock对象进行测试并提供与Spring和Hibernate相集成。Unitils设计成以一种高度可配置和松散偶合的框架来添加这些服务到单元...
包含junit-4.11.jar, dbunit-2.4.9.jar, unitils-3.3-with-dependencies.zip, mockito-1.9.5.zip
unitils整合dbunit利用excel进行单元测试 包含mock以及整合spring进行测试
详细介绍了Unitils的实用方法和步骤
Unitils,最好的单元测试工具,可以对DB,Spring等做模块测试
单元测试框架Unitils例子工程,集成了DBUnit,EasyMock.
Unitils源于尝试更加务实的单元测试,它始于一套测试准则,并为了方便应用这些准则而开发了一个开源代码库。
2009/8/31 1 接口测试的背景 11 什么是接口测试 12 为什么做接口测试 13 接口测试的适用范围 ...54 Unitils 55 TestNG 56 CruiseControl 57 Clover 58 Mock 6 接口测试的方向 7 参考资料 8 作者介绍
16.5.1 数据库测试的难点 16.5.2 扩展Dbunit用Excel准备数据 16.5.3 测试实战 16.6 使用unitils测试Service层 16.7 测试Web层 16.7.1 对LoginController进行单元测试 16.7.2 使用Spring Servlet API模拟对象 16.7.3 ...
16.5.1 数据库测试的难点 16.5.2 扩展Dbunit用Excel准备数据 16.5.3 测试实战 16.6 使用unitils测试Service层 16.7 测试Web层 16.7.1 对LoginController进行单元测试 16.7.2 使用Spring Servlet API模拟对象 16.7.3 ...
它的主要模块有:·DatabaseModule:测试数据库维护和连接池·DbUnitModule:使用DBunit进行测试数据维护·HibernateModule:Hibernate配置支持和自动的数据库mapping检查·MockModule:支持使用Unitils的mock框架进行...
单元测试 JUnit 断言 注解 mock Unitils spring 注解
改资源配准测试,使用的unitils+dbUtils的结合使用的。