如何在java中testingjdbc代码?

我想为连接到数据库的一些代码编写一些unit testing,运行一个或多个查询,然后处理结果。 (没有实际使用数据库)

另一位开发人员编写了我们自己的DataSource,Connection,Statement,PreparedStatement和ResultSet实现,它们将根据xmlconfiguration文件返回相应的对象。 (我们可以使用伪造的数据源,并对它返回的结果集运行testing)。

我们在这里重新发明轮子吗? 像unit testing已经存在这样的事情吗? 还有其他更好的方法来testingjdbc代码吗?

例如,您可以将DBUnit与一个可以从CSV文件读取其初始数据的HSQLDB一起使用。

你有几个select:

  • 用模拟库(例如JMock)来模拟数据库。 这个巨大的缺点是你的查询和数据很可能不会被testing。
  • 使用轻量级数据库进行testing,如HSQLDB 。 如果你的查询很简单,这可能是最简单的方法。
  • 为testing分配一个数据库。 DBUnit是一个很好的select,如果你使用的是Maven,你也可以使用sql-maven-plugin来正确设置和拆除数据库(注意testing之间的依赖关系)。 我推荐这个选项,因为它会给你最大的信心,查询适合你的数据库供应商。

有时将这些testingconfiguration为使这些testing仅在数据库可用时才执行是必要的和有用的。 这可以通过例如构build属性来完成。

我喜欢使用以下组合:

  • DBUnit的
  • HSQLDB
  • Unitils (特别是数据库testing和维护模块 )

只要使用DBUnit和HSQLDB就可以得到相当的效果。 Unitils提供了最后一英里的代码来pipe理和重置数据库状态。 它还提供了一个pipe理数据库模式更改的好方法,并使得使用特定的RBDMS(Oracle,DB2,SQL Server等)变得容易。 最后,Unitils为DBUnit提供了一些很好的包装,它使API现代化,使DBUnit更加愉快地工作。

如果你还没有检出Unitils,那你绝对应该这样做。 单位往往被忽视和低估。

使用任何模拟框架来完成这样的任务。 ( jMock 等 )

一些例子

这就是为什么你有derby (现在称为JavaDB)或sqlite–它们是小型的简单的数据库,你可以创build,加载,testing并相对快速和简单地销毁。

我会说HSQL是在unit testing期间要走的路。 你的testing点是testing你的jdbc代码,并确保它的工作。 添加自定义类或模拟jdbc调用可以很容易地隐藏错误。

我主要使用mysql,当testing运行的驱动程序类和URL更改为org.hsqldb.jdbcDriver和jdbc:hsqldb:mem:test。

我更喜欢使用EasyMock来testing一个不太容易的testing代码

有DBUnit 。 它不会允许你在没有数据库的情况下testing你的jdbc代码,但是你似乎可以通过模拟一个数据库来引入一组不同的购买。

尽pipe在应用程序中模拟jdbc的方式当然取决于您如何实现实际的jdbc事务。

如果你正在使用jdbc,我假设你已经编写了一个sorting实用程序类来完成DBUtils.getMetadataFor(String tablename)行中的一些任务。 这意味着你必须创build一个类的模拟,这可能是你所需要的。 这对你来说是相当简单的解决scheme,因为你显然已经有了一系列jdbc相关的模拟对象可用。 请注意,我假设你的jdbc代码没有在应用程序周围爆炸 – 如果是,重构!

如果你正在使用任何数据库处理框架(比如Spring框架的JDBC模板类),你可以并且应该使用EasyMock或其他一些等价物来模拟接口类。 这样,你就可以拥有世界上所有的力量来轻松地嘲弄连接。

最后,如果没有其他的工作,你可以做别人已经说过,并使用DBUnit和/或德比。

如果你想做unit testing,而不是集成testing,那么你可以使用非常基本和简单的方法,只使用Mockito,就像这样:

 public class JDBCLowLevelTest { private TestedClass tested; private Connection connection; private static Driver driver; @BeforeClass public static void setUpClass() throws Exception { // (Optional) Print DriverManager logs to system out DriverManager.setLogWriter(new PrintWriter((System.out))); // (Optional) Sometimes you need to get rid of a driver (eg JDBC-ODBC Bridge) Driver configuredDriver = DriverManager.getDriver("jdbc:odbc:url"); System.out.println("De-registering the configured driver: " + configuredDriver); DriverManager.deregisterDriver(configuredDriver); // Register the mocked driver driver = mock(Driver.class); System.out.println("Registering the mock driver: " + driver); DriverManager.registerDriver(driver); } @AfterClass public static void tearDown() throws Exception { // Let's cleanup the global state System.out.println("De-registering the mock driver: " + driver); DriverManager.deregisterDriver(driver); } @Before public void setUp() throws Exception { // given tested = new TestedClass(); connection = mock(Connection.class); given(driver.acceptsURL(anyString())).willReturn(true); given(driver.connect(anyString(), Matchers.<Properties>any())) .willReturn(connection); given(connection.prepareCall(anyString())).willReturn(statement); } } 

比你可以testing各种场景,如在任何其他Mockitotesting例如

 @Test public void shouldHandleDoubleException() throws Exception { // given SomeData someData = new SomeData(); given(connection.prepareCall(anyString())) .willThrow(new SQLException("Prepare call")); willThrow(new SQLException("Close exception")).given(connection).close(); // when SomeResponse response = testClass.someMethod(someData); // then assertThat(response, is(SOME_ERROR)); } 

Acolyte驱动程序可以用来模拟JDBC连接,在testing期间pipe理它,并返回数据作为结果集(使用types安全的行列表API): https : //github.com/cchantep/acolyte