【问题标题】:Writing Unit Tests for method that queries database为查询数据库的方法编写单元测试
【发布时间】:2012-01-25 12:26:10
【问题描述】:

我正在学习 TDD,我目前有一个可行的方法,但我想我应该尝试使用 TDD 重建它。

该方法本质上接受 6 个参数,查询数据库,执行一些逻辑并返回 List<T>

我的初始测试包括检查空/零定义的字符串和 int 方法参数值,但现在我不确定该怎么做。如果我不使用 TDD,我只需创建代码来查找数据库连接字符串并打开数据库连接、查询数据库、读取值等。

显然我们不能在单元测试中做到这一点,所以我在寻求一些关于如何进行的建议。

【问题讨论】:

  • Nitpick - 如果它查询数据库,它是一个集成测试,而不是一个单元测试。
  • @Oded:这是一个意见和争议的问题。
  • @Oded - 我在工作中多次说过这句话,它是不真实的!
  • @JohnSaunders - 我想这取决于一个人如何定义一个单元以及单元测试的约束应该是什么(速度、进程等)。

标签: c# .net unit-testing nunit


【解决方案1】:

请记住,TDD 更多的是关于良好的设计,而不是关于测试。这种方法太多了;它违反了关注点分离原则。

您已经确定了需要测试的几个领域:

该方法本质上采用 6 个参数,查询数据库,执行一些逻辑并返回 List<T>

你有几个独立的步骤,代码中可能还有更多隐藏的步骤。在涉及 TDD 时,将它们分解是游戏的名称。

对于初学者来说,将执行逻辑的部分分解出来可能是个好主意。

您的方法是动态构建查询吗?也拆开那部分并对其进行测试以确保查询正确编写。

您可以将查询的执行放入独立的存储库或类似的东西中,并针对它编写集成测试。这样一来,您只需对数据库进行简单的测试,而不是当前的复杂方法。

如果您尝试按原样进行测试,您最终可能会遇到一个需要大量设置并复制所有业务逻辑的怪物测试,并且当它中断时,您将不清楚出了什么问题.

【讨论】:

  • 所以我应该有一个模拟存储库,它只返回一个模拟数据库调用的内存数据列表?
  • 没错。你的逻辑可以对此采取行动。这使您在测试您正在执行的任何排序/过滤/处理时不必依赖数据库。它还可以防止您将来在数据库中发现导致测试“失败”的错误数据。
  • 我是基于从 DB/MockDB 返回信息的新方法编写测试还是基于现有方法编写测试以确保通过调用返回的新方法返回某些内容数据库信息?
  • 不确定我是否完全理解这个问题,但通常使用存储库模式,您会完全创建一个新类,例如CustomerRepository。然后您可以创建诸如GetByIdGetAll 之类的方法。您可以测试,给定有效的客户 ID,存储库返回具有该 ID 的客户,或者它返回包含多个客户的列表。您的逻辑将作用于 List<Customer>,而不会关心 List 的来源。
【解决方案2】:

一般来说,使用 TDD 测试数据库代码并没有什么“错误”。但是,您可以尝试抽象出数据库代码,然后将其模拟出来。

【讨论】:

  • 模拟它以从查询中返回数据片段?
  • 是的,差不多。返回特定测试的特定数据。
【解决方案3】:

该方法本质上需要 6 个参数,查询一个数据库,确实 一些逻辑并返回一个列表

这似乎是太多作为单元可测试代码!

可单元测试的代码应该做非常具体的事情,并在小模块中完成。因此,在您的情况下,您需要重构并将您的方法分解为以下(至少):

  • 数据库查询:包装在带有支持接口的 DataProvider 中。你的单元测试会模拟这个接口。
  • 做了一些逻辑:这是单元测试的最佳候选者。这应该是一个模块,它只接受数据提供者接口并执行逻辑并返回您将在单元测试中验证的修改列表。

另外,请记住,单元测试应涵盖每个可测试模块的至少三个场景:

  • 阳性测试
  • 阴性测试
  • 测试为无效值抛出有意义的异常。

希望这有帮助。

【讨论】:

    【解决方案4】:

    另一种选择是在测试之前启动事务并在之后进行回滚。这种方式测试是独立的,因此根据某些定义,仍然可以将其视为单元测试。

    与其他答案中提到的相反,您应该重构代码以在测试通过后获得更好的设计。然后你可以通过重新运行测试来验证你的重构没有破坏任何东西。

    【讨论】:

      【解决方案5】:

      您可能想尝试查看DbUnit 以在您的数据访问层上运行单元测试。它使您的数据库在测试运行之间处于已知状态,防止您的测试数据库损坏。

      【讨论】:

      • 任何 .NET 等价物?这个问题是 .NET 特定的。
      • @DannyVarod 快速谷歌搜索发现了这个项目:dbunit-net.sourceforge.net
      • 不错,但特定于 DAL 技术。将演示数据库文件保存在源代码管理中,然后复制和附加会更加灵活。
      【解决方案6】:

      你可以:

      1. 使用类/测试 init 生成一个空白 DB 或具有已知数据集的小型 DB 副本。
      2. 在测试方法中输入测试数据(如果数据库为空),然后执行查询,然后将结果与期望结果进行比较。
      3. 在测试/类清理中删除 DB。

      这会测试您的单元,但被某些人视为“集成测试”。 - 由于“单元”一词的歧义,“单元测试”一词存在一些分歧。

      您还可以使用内存数据库或进程内数据库来简化测试环境。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-11-01
        • 2018-07-31
        • 1970-01-01
        • 1970-01-01
        • 2010-11-16
        • 2020-08-19
        • 1970-01-01
        相关资源
        最近更新 更多