如何在 java 中对 jdbc 代码进行单元测试? [关闭]

Posted

技术标签:

【中文标题】如何在 java 中对 jdbc 代码进行单元测试? [关闭]【英文标题】:How do I unit test jdbc code in java? [closed] 【发布时间】:2010-09-20 22:48:15 【问题描述】:

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

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

我们是在重新发明***吗?单元测试是否已经存在类似的东西? 还有其他/更好的方法来测试 jdbc 代码吗?

【问题讨论】:

【参考方案1】:

您有多种选择:

使用 Mock 库模拟数据库,例如JMock。这样做的巨大缺点是您的查询和数据很可能根本不会经过测试。 使用轻量级数据库进行测试,例如HSQLDB。如果您的查询很简单,这可能是最简单的方法。 为测试指定一个数据库。 DBUnit 是一个不错的选择,或者如果您使用的是 Maven,也可以使用 sql-maven-plugin 正确设置和拆除数据库(注意测试之间的依赖关系)。我推荐这个选项,因为它会给你最大的信心,让你的查询与你的数据库供应商一起正常工作。

有时使这些测试可配置是必要且有用的,以便仅在数据库可用时执行这些测试。这可以通过例如来完成构建属性。

【讨论】:

谢谢我喜欢使用 maven 设置/拆除数据库的想法。我们现在使用 maven 进行构建,所以这对我们来说很容易使用。 DBUnit 链接 (dbunit.org) 指向一个可能与 DBUnit 无关的中文网站。 @user3885927 我修复了链接。下次您发现此类情况时,请随时提交修改以修复损坏的链接。【参考方案2】:

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

【讨论】:

你能提供任何例子吗?我正在寻找示例,但找不到任何易于理解的示例。我正在使用 maven。【参考方案3】:

我喜欢使用以下组合:

DBUnit HSQLDB Unitils(具体来说,database testing 和 maintenance modules)

您可以仅使用 DBUnit 和 HSQLDB。 Unitils 提供了最后一英里的代码来管理和重置数据库状态。它还提供了一种管理数据库模式更改的好方法,并且可以轻松使用特定的 RBDMS(Oracle、DB2、SQL Server 等)。最后,Unitils 围绕 DBUnit 提供了一些很好的包装器,它使 API 现代化并使 DBUnit 更易于使用。

如果您还没有检查过 Unitils,那么您绝对应该检查过。 Unitils 经常被忽视和低估。

【讨论】:

这也是我倾向于使用的堆栈。 DBUnit/H2/Unitils【参考方案4】:

这就是您拥有derby(现在称为JavaDB)或sqlite 的原因——它们是小型、简单的数据库,您可以相对快速而简单地创建、加载、测试和销毁它们。

【讨论】:

但是任何依赖于供应商特定 SQL 且不受轻量级数据库支持的代码都将无法测试。 @Asaph:“供应商特定的 SQL”通常是一个错误。但是,当您去测试特定于供应商的 SQL 时,您并没有进行单元测试,所以这并不是真正的单元测试问题,是吗? 在这一点上,它更像是一个集成测试而不是一个单元测试。但是在 JUnit 测试中连接到 mysql 可以说与从 JUnit 测试中连接到 sqlite 没有根本的不同。我将这两种情况都视为集成测试。真正使它成为 unit 测试的是在所有数据库接缝处进行模拟或伪造,即。根本没有数据库服务器(轻量级或重量级)。话虽如此,我并不热衷于始终坚持这一原则。只要测试运行快并且不需要大量手动设置,我就可以。 @Asaph:模拟数据库——虽然在技术上是可行的——但通常是愚蠢的。你不写它,因此你必须信任它。如果您不信任它,请停止考虑它,并找到您信任的东西。既然你信任它,就用它来测试。你信任你的测试框架。 (你不测试它,是吗?)你信任你的编译器和库。也可以信任 JDBC 服务。【参考方案5】:

我会说 HSQL 是您在单元测试期间要走的路。您的测试重点是测试您的 jdbc 代码并确保其正常工作。添加自定义类或模拟 jdbc 调用可以轻松隐藏错误。

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

【讨论】:

【参考方案6】:

我更喜欢使用EasyMock 来测试不容易测试的代码

【讨论】:

【参考方案7】:

如果你想做单元测试,而不是集成测试,那么 您可以使用非常基本且简单的方法,仅使用 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 (e.g 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);        
    

您可以测试各种场景,就像在任何其他 Mockito 测试中一样,例如

@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));

【讨论】:

【参考方案8】:

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

【讨论】:

【参考方案9】:

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

如果您按原样使用 jdbc,我假设您已经为自己编写了一个实用程序类来执行DBUtils.getMetadataFor(String tablename) 行中的一些任务。这意味着您必须创建该类的模拟,而这可能就是您所需要的。这对您来说是一个相当简单的解决方案,因为您显然已经有一系列可用的 jdbc 相关模拟对象。请注意,我假设您的 jdbc 代码没有在应用程序周围爆炸 - 如果是,请重构!!!

但是,如果您使用任何数据库处理框架(如 Spring Framework 的 JDBC 模板类),您可以并且应该使用 EasyMock 或其他等效物来模拟接口类。这样,您就可以拥有轻松模拟连接所需的所有功能。

最后,如果没有其他方法,您可以按照其他人已经说过的方式使用 DBUnit 和/或 derby。

【讨论】:

【参考方案10】:

我们使用 Mockrunner。 http://mockrunner.sourceforge.net/ 它内置了模拟连接和数据源,因此无需您自己实现。

【讨论】:

【参考方案11】:

Acolyte 驱动程序可用于模拟 JDBC 连接,在测试期间对其进行管理并将数据作为结果集返回(使用其类型安全的行列表 API):https://github.com/cchantep/acolyte

注意:我是 Acolyte 的作者。

【讨论】:

你能通过这些***.com/… 并检查它们是否自我披露。如果你完成后可以在这里回复。谢谢。【参考方案12】:

看看JDBDT:http://jdbdt.org

您可以将它用于数据库设置和断言,作为 DBUnit 的替代品。

注意:我是 JDBDT 的作者。

【讨论】:

以上是关于如何在 java 中对 jdbc 代码进行单元测试? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何在订阅Angular7单元测试用例中对代码进行单元测试

如何在验证方法 nuxtjs vuejs jest 中对代码进行单元测试

如何在打字稿中对模型接口进行单元测试?

如何在 Flutter 中对依赖于 3rd-Party-Package 的代码进行单元测试?

如何在 C++ 中对受保护的方法进行单元测试?

如何在 Gatsby 中对 GraphQL 查询进行单元测试