【问题标题】:Testing Side Effects in BDDs在 BDD 中测试副作用
【发布时间】:2020-01-13 17:38:24
【问题描述】:

我有一个具有以下逻辑的 API:

  1. 从 Kafka 消费。
  2. 处理记录。
  3. 如果处理成功,请更新数据库。
  4. 如果处理失败,则将其推送到 Kafka 主题。
  5. 如果推送到 Kafka 主题失败,则提交。
  6. 如果记录处理成功,则提交。
  7. 如果提交失败,则记录并继续使用下一个事件。

我正在为此 API 编写 BDD。目前,我觉得我正在测试太多场景:

  1. ProcessingFailed -> 数据库未更改 -> 应将事件推送到 Kafka -> 应提交。
  2. Kafka 推送失败 -> 应该提交。
  3. 提交失败->(怎么办?要检查日志是否打印正确吗?)
  4. 快乐路径 -> 数据库已更新 -> Kafka 主题不包含事件 -> 提交成功。

我的问题是,测试此类副作用的正确方法是什么?

现在假设我的流程步骤由三个步骤组成:

  1. 从数据库中获取。
  2. 进行 HTTP 调用。

现在假设我通过关闭数据库来模拟“处理失败”。现在我还需要测试是否没有进行 HTTP 调用吗?

【问题讨论】:

    标签: unit-testing testing tdd integration-testing bdd


    【解决方案1】:

    bdd 测试的一个很好的一般规则是每个测试应该只有一个失败的原因。对于黄瓜来说,这意味着在每个场景中只有一个Then 步骤。

    以此为指导,我建议在流程的每个步骤中编写一个场景。

    # Consume from Kafka
    Given a certain thing has happened
    # Process the record
    When some action is performed successfully
    # Update database if processed successfully
    Then some result exists in the database
    

    然后你的下一个场景从第一个场景停止的地方开始:

    Given a certain thing happened
    When the action is performed unsuccessfully
    # Push failed message to Kafka queue
    Then a failed message is sent
    

    第三种情况在第二种情况下接续:

    Given a certain thing happened
    And the action was performed unsuccessfully
    When a failure message is sent
    Then a thing should not exist in the database
    

    每个场景都建立在前面场景中验证的步骤之上,小心确保场景不共享数据,或者依赖于之前执行的场景的成功。

    【讨论】:

    • 我通常认为“一个失败的原因”意味着只有一个“当”而不是一个“那么”(即使那样也有例外)。例如,考虑从 ATM 取钱。你拿到钱了,你的银行账户也被借记了;这两者必须同时发生,所以 IMO 应该出现在同一场景中。这是非常典型的交易。如果它是另一个利益相关者的单独结果(可独立交付),那么可以,将它们放在单独的场景中,因为它是一种不同的能力,恰好对其行为具有相同的触发器。
    • @Lunivore:我明白你的意思,但我一直认为 BDD 测试与你期望​​的状态变化有关。如果单个状态更改导致您的测试由于多种原因而失败,人们会认为该测试不稳定或不稳定。同样的规则也适用于单元测试。你希望失败是: A) 单一的; B) 易于识别。拥有一个Then 会给您带来预期 的单点故障。如果您考虑一下,Given 是已经发生的When,因此大多数 BDD 测试已经有多个 When
    • 您认为 BDD 的主要目的是测试。尝试将它们视为自动化场景和动态文档。如果做得好,它可以帮助人们了解软件如何/为什么工作以及应该防止错误。抓住他们应该是一件罕见的事情。如果您主要使用 BDD 进行回归测试,请使用更多类级别的 TDD / BDD 来帮助分离关注点并提高质量。吉文斯并不总是发生在什么时候。例如,我们经常在不通过 UI 或 API 的情况下设置数据。 Given 的设置方式(或者是谁做的!)并不重要。
    • 简短版:我更重视在阅读自动化场景和单元测试时使它们易于理解,而不是在它们失败时使它们易于理解。他们那样失败的少。
    【解决方案2】:

    目前,我觉得我正在测试太多场景 我的问题是,测试这种副作用的正确方法是什么?

    嗯,听起来你在描述一个状态机;其中转换由协议中不同效果的表示驱动。

    鉴于此,我通常希望看到针对每个目标状态的测试。

    根据您对风险的评估,在许多不同的粒度上运行自动检查可能是有意义的 - 大量解耦测试探索状态机本身的不同极端情况,一些检查以确保不同效果的编排是正确的,需要进行一些测试以确保将它们连接在一起时整个混乱工作。

    现在我还需要测试 HTTP 调用是否没有进行吗?

    这里可能有两个重要的问题要问自己:

    1. 不进行自动化测试有哪些风险?
    2. 为什么只是添加测试并不容易?

    如果测试科目“简单到明显没有缺陷”,那么投资赔率告诉我们,投入时间和金钱进行额外测试并不是一个有利的玩法。

    另一方面,如果您正在寻找不测试事物的借口,那么您可能希望对您的设计持批判态度。 尤其是,如果您在“已经工作”的模块中添加/更改代码,则更是如此。测试投资的一大回报来自对我们定期更改的代码进行许多简单准确的测试,因此不愿为您正在更改的代码添加新测试是一个大红旗[tm],表明某些事情不符合计划。

    【讨论】:

      猜你喜欢
      • 2012-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-27
      • 1970-01-01
      • 2020-03-19
      • 1970-01-01
      • 2014-03-29
      相关资源
      最近更新 更多