4

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

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

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

4

4 回答 4

11

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

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

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

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

于 2013-08-20T03:47:15.820 回答
2

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

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

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

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

于 2013-08-20T03:53:21.010 回答
2

一些意见/建议:

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

对于基于 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 。

于 2014-01-15T09:15:39.660 回答