如何在 Java 中对 DAO 应用单元测试

Posted

技术标签:

【中文标题】如何在 Java 中对 DAO 应用单元测试【英文标题】:How to apply unit test on DAOs in java 【发布时间】:2013-08-22 00:04:44 【问题描述】:

我不知道如何在数据访问层应用单元测试。我总是想知道是否应该测试数据访问层。在我公司,我们有稳定的数据库来存储单元测试数据和测试数据访问层,通过运行数据访问对象并检查它们从稳定数据库中获取的数据。

为了通过单元测试,稳定数据库中的数据不能再修改。我认为有一个更好的解决方案。如果我没记错的话,mock 对象不能对 SQL 语句和ResultSet 映射进行测试。

对 DAO 进行单元测试的最佳方法是什么?有没有更好的方法来使用 TDD 做到这一点?

【问题讨论】:

你可以试试 DBUnit。它允许您创建数据集,以便您的测试用例可以对这些数据集进行操作。在执行测试之前,您可以将数据集中的测试数据初始化到数据库中。这将使您拥有可重复的测试结果和“稳定”的数据库。 【参考方案1】:

首先,根据大多数定义,“单元”测试不依赖于数据库等外部系统。您想要创建所谓的“功能”或“集成”测试。在实践中,这些类型的测试将以与单元测试相同的方式实现,使用类似 Junit 的东西,但你应该将它们与单元测试分开,单元测试应该运行得非常快,并且在你的数据库关闭或数据发生变化时不会中断。

其次,尽量将大部分业务逻辑排除在 DAO 之外,而是将其放入服务 POJO 层,这样您就可以在不涉及数据库的情况下测试业务逻辑。

接下来,为 DAO 设置测试的理想方法是从一个空数据库开始,并用测试数据加载它(通常使用 DAO 本身),然后针对已知的可写测试运行 DAO 测试数据集。如果您有幸拥有只读数据库,那么您概述的 stable database 方法将起作用,但大多数系统都是对数据库进行读/写的。

最后,测试 DAO 很有价值。数据库查询通常是系统中最脆弱的部分,您不想等到将它们部署到生产环境时才发现它们出现问题。

【讨论】:

非常好。事实上,包含任何形式的业务逻辑的 DAO不是 DAO:它是一个 MESS :-)【参考方案2】:

一些cmets/建议:

    DAO 测试旨在验证触发的查询和检索的数据是否符合预期。在 DAO 中几乎不应该有任何业务逻辑需要测试。 由于主要目标是测试数据库交互,模拟不会让它万无一失,特别是边缘情况。 鉴于此,您现在采用的方法足够公平。我不知道你为什么觉得它不好。稍微详细说明会有所帮助。 如果你不方便使用外部数据库,那么你可以使用Java内置的javaDB。请注意,在运行此测试之前先创建测试数据会产生开销。

【讨论】:

恕我直言,这不好,因为 OP 要求进行 unit 测试。他/她的设置不是单元测试。 好吧,那么单元测试在 DAO 中可能没有任何用途。测试代码的唯一自动化测试是 OP 已经在做的事情。 并非如此。要对业务逻辑进行单元测试,她/他可以使用另一个答案中提到的 DBUnit。针对真实数据库的“单元测试”不是单元测试。按照同样的逻辑,我们可以说一般的单元测试没有任何用途,因为在功能或集成测试期间会检测到任何问题。 主要问题是术语之一。许多人将“单元测试”称为任何形式的自动化测试,尤其是功能测试和集成测试。这是不正确的。单元、组件、功能和集成测试都可以是手动或自动化的。【参考方案3】:

严格来说,您正在编写功能测试。为此,您将需要一种或另一种测试数据库。让我们谈谈您的选择。

    HSQL/内存数据库。小而快。设置和滚动很简单,并且在单元测试大小的数据上表现出色。不利的一面是,除非您使用这些环境进行部署,否则您可能会有单元测试工作但实际代码失败的风险。这也意味着您不能使用 HSQL 和生产数据库都不支持的任何 SQL 构造。这可以通过使用 Hibernate 或类似方法在一定程度上缓解。如果您只有非常简单的查询,这是一个很好的方法。

    完全模拟数据库调用。除非你在 DAO 中做太多繁重的工作,否则毫无意义。

    使用生产数据库的测试实例。这将在准确性或结果方面为您提供最佳结果。它可以让您测试以确保您的所有调用都按预期工作,并允许您使用不可移植的 SQL。您可以使用 DBUnit 之类的东西来加载数据库数据,或者只使用正在测试的 DAO 来执行此操作。如果您有大而讨厌的查询,我会推荐这个。具有大量边缘案例、汇总视图和微妙行为的案例。缺点是真正的数据库会导致性能损失,因为它们会做真正的工作(事务、索引更新、回滚支持)。

【讨论】:

【参考方案4】:

对于基于 JDBC 的项目,可以模拟 JDBC 连接,这样就可以在没有实时 RDBMS 的情况下执行测试,每个测试用例都是隔离的(没有数据冲突)。

它允许验证持久性代码传递正确的查询/参数(例如https://github.com/playframework/playframework/blob/master/framework/src/anorm/src/test/scala/anorm/ParameterSpec.scala)并按预期处理 JDBC 结果(解析/映射)。

类似 jOOQ 的框架或我的框架 Acolyte 可用于:https://github.com/cchantep/acolyte。

【讨论】:

以上是关于如何在 Java 中对 DAO 应用单元测试的主要内容,如果未能解决你的问题,请参考以下文章

如何在 java 中对这个方法进行单元测试?

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

在 C# 中对“不可测试”的应用程序进行自动化测试。单元/集成/功能/系统测试 - 如何?

如何在没有ORM的情况下对DAO进行单元测试

如何从 IDE 或构建脚本中对 Flex 应用程序进行单元测试?

如何使用 Spring Security 对 Spring 4 DAO 方法进行单元测试?