测试驱动的开发真是太好了! 在组织中建立它之后,您将开始:
- 极大地提高您的质量(事情不常发生)
- 大大改善您的流程(事情可以更轻松地更改)
- 极大地改善您的开发人员氛围(事情更有趣)
进行正确的测试驱动开发的重要性是找到要覆盖的代码的良好比例。
- 通过自动单元测试
- 通过自动集成测试
- 通过手动“烟雾测试”
- 通过手动的“验收测试”
- 一点也不
找到该比例可以作为激烈的宗教讨论的依据。 我很快将在博客中发表关于该主题的个人看法。 但是,在本文中,我们将重点介绍第一种测试: 单元测试 。
单元测试您的数据访问
当涉及数据库时,人们可能会很快跳到编写集成测试,因为他们要做的就是创建一个小的Derby,H2或HSQLDB(或其他)测试数据库,并在实际运行之前运行几个数据设置查询。测试。 希望他们的代码模块不会注意到对生产环境的影响,并且整个系统可以作为黑箱进行测试。 这样做的好处是可以以验证您的业务需求,用户案例或任何您称呼的方式编写测试。 到目前为止,理论。
当这些数据库集成测试堆积如山时,将它们相互隔离变得越来越困难。 避免相互依赖,同时避免昂贵的数据库设置非常困难。 构建/提交后,您将无法立即运行整个测试套件。 您需要每晚构建,每周构建。 但是对数据访问层进行单元测试并没有那么容易! 因为JDBC是一个可怕的API,所以很难模仿。 通过这种高度状态化的API配置和执行查询的方法有很多,您的单元测试很快就变得难以管理。
有一些库可以帮助您进行数据库测试。 仅举几个:
- MockRunner :这具有一些特定于JDBC的扩展,这些扩展允许模拟JDBC结果集以及检查是否执行了实际查询
- jMock :一个“普通” Java模拟库
- mockito :一个“普通的” Java模拟库
- DBUnit :这不会模拟您的数据库,对测试数据库很有用。 另一个用例,但仍然值得一提
上述某些库无法解决JDBC是一个难以模仿的API的事实,特别是如果您需要同时支持多个(不兼容!)版本的JDBC时。 一些示例可以在这里看到:
- http://stackoverflow.com/questions/10128185/using-jmock-to-write-unit-test-for-a-simple-spring-jdbc-dao
- http://www.thedwick.com/2010/01/resultset-mocking-with-jmock
- http://www.turnleafdesign.com/mocking-jdbc-connections-with-mockrunner
用jOOQ模拟数据库
在应用程序中使用jOOQ时,在jOOQ 3.0中对数据库进行模拟变得非常容易。 jOOQ现在还提供了Mock JDBC Connection 。 但是,与其他框架不同,您只需要使用jOOQ实现单个功能接口,并将该实现提供给MockConnection: MockDataProvider 。 这是一个简单的实现示例:
MockDataProvider provider = new MockDataProvider() {
// Your contract is to return execution results, given a context
// object, which contains SQL statement(s), bind values, and some
// other context values
@Override
public MockResult[] execute(MockExecuteContext context)
throws SQLException {
// Use ordinary jOOQ API to create an org.jooq.Result object.
// You can also use ordinary jOOQ API to load CSV files or
// other formats, here!
Result<MyTableRecord> result = executor.newResult(MY_TABLE);
result.add(executor.newRecord(MY_TABLE));
// Now, return 1-many results, depending on whether this is
// a batch/multi-result context
return new MockResult[] {
new MockResult(1, result)
};
}
};
// Put your provider into a MockConnection and use that connection
// in your application. In this case, with a jOOQ Executor:
Connection connection = new MockConnection(provider);
Executor create = new Executor(connection, dialect);
// Done! just use regular jOOQ API. It will return the values
// that you've specified in your MockDataProvider
assertEquals(1, create.selectOne().fetch().size());
上面的实现充当JDBC的各种executeXXX()方法的回调。 通过非常简单的MockExecuteContext API ,您可以:
- 获取对已执行的SQL的访问并绑定值(使用通用jOOQ API将绑定值内联到SQL语句中)
- 区分常规SQL语句与单语句/多绑定值和多语句/无绑定值批处理
- 使用jOOQ的org.jooq.Result对象返回一个或几个结果(您可以轻松地从CSV,XML,JSON,TEXT格式导入)
- 通过相同的API返回“生成的密钥”结果
- 让jOOQ的MockStatement负责通过JDBC API对模拟数据进行序列化
还有一个MockFileDatabase的实验性实现, MockFileDatabase是使用以下格式的基于文本的模拟数据库:
# This is a sample test database for MockFileDatabase
# Its syntax is inspired from H2's test script files
# When this query is executed...
select 'A' from dual;
# ... then, return the following result
> A
> -
> A
@ rows: 1
# Just list all possible query / result combinations
select 'A', 'B' from dual;
> A B
> - -
> A B
@ rows: 1
select 'TABLE1'.'ID1', 'TABLE1'.'NAME1' from 'TABLE1';
> ID1 NAME1
> --- -----
> 1 X
> 2 Y
@ rows: 2
MockFileDatabase实现了MockDataProvider,因此为单元测试提供示例数据非常简单。 jOOQ的未来版本将允许:
- 正则表达式模式匹配的SQL语句以提供模拟结果
- 从其他格式加载这些结果,例如jOOQ支持的导出格式
- 指定批处理语句,多结果语句等的行为。
在其他上下文中使用jOOQ的MockConnection
事情不止于此。 由于jOOQ的MockConnection是jOOQ的此模拟子API的入口,因此您也可以在其他环境中使用它,例如在运行JPA查询,Hibernate查询,iBatis或仅使用普通的旧式JDBC查询时。
jOOQ刚刚成为您首选的JDBC模拟框架!
参考:在JAVA,SQL和JOOQ博客上,我们的JCG合作伙伴 Lukas Eder 轻松模拟了您的数据库 。
翻译自: https://www.javacodegeeks.com/2013/02/easy-mocking-of-your-database.html