`
alfred.w
  • 浏览: 92608 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Unitils 使用指南[翻译]-数据库测试

阅读更多

 

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注解中标明。例如你可以建立一个DbUnitXlsDataSet通过实现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>
 

这个例子我们定义了两个方案,ABschema-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在你的应用代码里。实际上对用户来说那是透明的。

如果你继承了UnitilsSpring,并且你已经配置了bean的类型PlatformTransactionManager Spring配置里。Unitils会使用这个事务管理器。

 

分享到:
评论

相关推荐

    unitils-3.3-with-dependencies.zip

    - `unitils-jdbc.jar`:数据库测试支持模块。 - `unitils-mock.jar`:模拟对象模块。 - `unitils-orm.jar`:ORM测试支持模块。 - `unitils-testng.jar`或`unitils-junit.jar`:针对TestNG或JUnit的适配器。 - `lib/`...

    spock-unitils-0.7-groovy-2.0.zip

    标题 "spock-unitils-0.7-groovy-2.0.zip" 暗示这是一个软件库,可能是一个测试框架或工具,结合了Spock、Unitils和Groovy技术。Spock是一个基于JVM的BDD(行为驱动开发)框架,主要针对Groovy和Java语言,提供了一...

    使用Unitils测试DAO

    此类可能包含方法来初始化数据集、执行数据库操作、比较数据集等,简化了使用Unitils进行数据库测试的流程。 5. **源码解析**: 分析DBUnitUtils类的源码可以帮助我们理解作者是如何结合Unitils与DBUnit进行DAO...

    Unitils-core-3.3.jar

    Unitils-core-3.3的jar包

    Unitils单元测试

    Unitils的模块化设计是其另一大特点,包括unitils-core(核心模块)、unitils-database(数据库管理)、unitils-DbUnit(DbUnit集成)、unitils-easymock(EasyMock支持)、unitils-inject(对象注入)、unitils-...

    Unitils教程(介绍Unitils的最佳资料)

    Unitils 提供了一些实用的工具和方法来帮助我们编写数据库测试。 例如,我们可以使用 Unitils 的 DatabaseModule 来测试数据库操作。DatabaseModule 提供了一些实用的方法来操作数据库,例如创建、删除和更新数据库...

    Unitils-jar包

    Unitils 测试框架目的是让单元测试变得更加容易和可...支持数据库测试,支持利用Mock 对象 进行测试并提供与Spring 和Hibernate 相集成。Unitils 设计成以一种高度可配置和松散耦 合的方式来添加这些服务到单元测试中

    Unitils示例

    它支持 JUnit 和 TestNG,提供了多种测试模块,如数据库测试、ORM 支持(如 Hibernate 和 iBatis)、模拟对象等。在本示例中,我们看到 Unitils 被用来处理与数据库相关的测试和对象模拟。 2. **DBUnit 集成** ...

    Integrete unitils for database(dao) testing

    描述中提到的链接没有具体内容,但通常在博客文章中,作者可能会详细解释如何配置和使用Unitils进行数据库测试,分享实际示例代码,以及解决可能遇到的问题和最佳实践。 标签“源码”和“工具”表明该博文可能涉及...

    unitils-2.2

    对于数据库测试,它支持自动配置数据库连接,以及在测试前后自动清理数据,避免了测试间的干扰。此外,它还提供了事务管理功能,可以在测试完成后回滚所有的数据库更改,保持数据一致性。 对于Spring框架的支持,...

    unitils整合dbunit利用excel进行单元测试

    unitils整合dbunit利用excel进行单元测试 包含mock以及整合spring进行测试

    unitils-selenium:使用 Selenium 测试 Web 应用程序的 Unitils 模块-开源

    Unitils 模块 - 启动 Selenium Web 驱动程序以测试 Web 应用程序的简单方法。

    对dbunit进行mybatis DAO层Excel单元测试(必看篇)

    在使用dbunit之前,需要在pom.xml文件中添加相关的依赖项,包括unitils-core、unitils-dbunit、unitils-io、unitils-database和unitils-spring等。同时,需要在resource文件夹下创建一个unitils.properties配置文件...

    junit单元测试jar包集

    **Unitils** 是一个集成了多种测试辅助功能的框架,`unitils-3.3-with-dependencies.zip`包含了其3.3版本及其所有依赖。Unitils扩展了JUnit的功能,提供了数据库、ORM(对象关系映射)支持,如Hibernate和iBatis的...

    Unitils框架与模块扩展

    Unitils构建在DBUnit与EasyMock项目之上并与JUnit和TestNG相结合,支持数据库测试,支持利用mock对象进行测试并提供与Spring和Hibernate相集成。Unitils设计成以一种高度可配置和松散偶合的框架来添加这些服务到单元...

    改资源配准测试

    Unitils与DBUtils的结合使用,进一步增强了数据库测试的能力。DBUtils是Apache的一个开源项目,提供了一套简单实用的数据库操作API,包括连接池管理、SQL执行等基础功能。在测试中,DBUtils可以辅助Unitils执行...

    接口测试白皮书--淘宝(中国)软件有限公司

    对于复杂的接口测试场景,Unitils 可以简化对象初始化、数据库操作等任务。 ##### 5.5 TestNG TestNG 是一个用于 Java 的测试框架,它提供了丰富的功能集,如并行测试执行、参数化测试等。对于接口测试而言,TestNG...

    Unitil学习

    单元测试中通常涉及到几个重要方面,比如断言(Assertion)、数据库测试、与Spring框架的集成、使用Mock Objects进行测试以及支持如EasyMock等模拟框架。Unitils提供了一个丰富的工具集,能够简化这些测试环节中的...

Global site tag (gtag.js) - Google Analytics