有效的 BDD 场景步骤?给定->当->然后->什么时候

发布于 2024-09-17 08:56:06 字数 542 浏览 5 评论 0原文

如果我定义了以下步骤,这是有效的场景吗?我感觉这是某种气味。

Scenario: Change users status
   Given I have the following users exist:
        | code | status   |
        | u1   | active   |
        | u2   | inactive |
        | u3   | active   |
     And the status filter is "active"
    When I update "u1" to "inactive" 
    Then I should see the following users:
        | code |
        | u3   |
    When I change status filter to "inactive"
    Then I should see the following users:
        | code |
        | u1   |
        | u2   |

If I have the following steps defined, is this valid scenario? I feel like it is some kind of smell.

Scenario: Change users status
   Given I have the following users exist:
        | code | status   |
        | u1   | active   |
        | u2   | inactive |
        | u3   | active   |
     And the status filter is "active"
    When I update "u1" to "inactive" 
    Then I should see the following users:
        | code |
        | u3   |
    When I change status filter to "inactive"
    Then I should see the following users:
        | code |
        | u1   |
        | u2   |

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

有木有妳兜一样 2024-09-24 08:56:06

Liz 对系统功能的描述是正确的。我还建议场景中只有一个 When 。因为每个场景(我认为)都应该验证系统在发生某事时从给定状态进入然后状态。

在这种情况下,我还建议有两个不同的功能。一个功能是您的应用程序可以更改用户状态(激活/停用):

Feature: Changing user status

Scenario: Deactivating user
   Given following users exist:
        | code | status   |
        | u1   | active   |
        | u2   | inactive |
        | u3   | active   |
    When user u1 is deactivated
    Then following users exist:
        | code | status   |
        | u1   | inactive |
        | u2   | inactive |
        | u3   | active   |

另一个功能是您可以按状态过滤用户:

Feature: Filtering users

Scenario: Filtering active users
   Given following users exist:
        | code | status   |
        | u1   | active   |
        | u2   | inactive |
        | u3   | active   |
    When I filter for active users
    Then I should see the following users:
        | code |
        | u1   |
        | u3   |

Scenario: Filtering inactive users
   Given following users exist:
        | code | status   |
        | u1   | active   |
        | u2   | inactive |
        | u3   | active   |
    When I filter for inactive users
    Then I should see the following users:
        | code |
        | u2   |

在这种情况下,当其中一个场景被破坏时,您就会知道原因。它要么没有改变用户的状态,要么没有正确过滤它们。您知道您的应用程序中的哪个功能被破坏了。

Liz is right about describing capabilities of system. I would also suggest to have only one When in scenario. Because each scenario (I think) should verify that system goes from Given state to Then state When something happens.

In this case I also suggest to have two different features. One feature is about your application can change user status (activate/deactivate):

Feature: Changing user status

Scenario: Deactivating user
   Given following users exist:
        | code | status   |
        | u1   | active   |
        | u2   | inactive |
        | u3   | active   |
    When user u1 is deactivated
    Then following users exist:
        | code | status   |
        | u1   | inactive |
        | u2   | inactive |
        | u3   | active   |

Another feature is about you can filter users by status:

Feature: Filtering users

Scenario: Filtering active users
   Given following users exist:
        | code | status   |
        | u1   | active   |
        | u2   | inactive |
        | u3   | active   |
    When I filter for active users
    Then I should see the following users:
        | code |
        | u1   |
        | u3   |

Scenario: Filtering inactive users
   Given following users exist:
        | code | status   |
        | u1   | active   |
        | u2   | inactive |
        | u3   | active   |
    When I filter for inactive users
    Then I should see the following users:
        | code |
        | u2   |

In this case when one of the scenarios is broken, you will know the reason. It's either not changing status of user, or not filtering them properly. You know which feature is broken in your application.

后来的我们 2024-09-24 08:56:06

您用相当代码驱动的术语来描述它,但除此之外它是一个有效的场景。

如果您想让它变得更好,您可以根据系统的功能,用用户可能用来描述他们正在做的事情的语言来描述它:

Scenario: Change users status
   Given these users exist:
        | code | status   |
        | u1   | active   |
        | u2   | inactive |
        | u3   | active   |
    And we filter for active users
    When I disable user u1
    Then I should see the following users:
        | code |
        | u3   |
    When we filter for inactive users
    Then I should see the following users:
        | code |
        | u1   |
        | u2   |

您还可以使用更典型的用户名,以便阅读它的人了解什么这些名字一目了然(Lunivore、Soe、Jon,而不是 u1 和 u2)。

没那么大区别。您认为什么是难闻的气味?只是语言的问题吗?

You're describing it in quite code-driven terms, but otherwise it's a valid scenario.

If you wanted to make it better, you could describe it in terms of the capabilities of the system, in the language that users might use to describe what they're doing:

Scenario: Change users status
   Given these users exist:
        | code | status   |
        | u1   | active   |
        | u2   | inactive |
        | u3   | active   |
    And we filter for active users
    When I disable user u1
    Then I should see the following users:
        | code |
        | u3   |
    When we filter for inactive users
    Then I should see the following users:
        | code |
        | u1   |
        | u2   |

You could also use more typical usernames so that people reading it understand what those names represent at a glance (Lunivore, Soe, Jon instead of u1 and u2).

Not so much difference. What did you identify as a bad smell? Was it just the language?

甜味拾荒者 2024-09-24 08:56:06

通常,最好只有一个“何时”步骤,因为这就是您实际测试的内容。然而,有时我发现指定整个用例也很有用,其中可能包括多个相互依赖的 then 和 when 步骤。例如:

 when a new user registers
 then the user receives an email confirmation
 when the email confirmation is confirmed by the user
 then the user is registered 

但是,在您的示例中,您确实应该编写两个测试,因为您实际上测试了两个不直接相互依赖的不同功能。

Typically it is good to just have one 'when' step, because that is what you actually test. However, sometimes I find it also useful to specify whole use cases that might include several then and when steps that depend on each other. For example:

 when a new user registers
 then the user receives an email confirmation
 when the email confirmation is confirmed by the user
 then the user is registered 

In your example, however, you really should write two tests, because you actually test two different features that also do not directly depend on each other.

回忆凄美了谁 2024-09-24 08:56:06

总体而言,

BDD 实际上是使用不同术语的合同设计。一般来说,BDD采用Given-When-Then的形式,大致类似于先决条件(Given)、检查条件/循环不变量(When)和后置条件/不变量(Then)。

注意

请注意,BDD 非常类似于 Hoare 逻辑(即 {P}C{Q} 或 {P}recondition-[C]ommand-{Q}Post-condition)。因此:

  • 前提条件(给定)必须成立才能使命令(方法/函数)正确计算。任何违反给定(前提条件)的行为都会表明调用客户端代码中存在错误。
  • 命令(何时)是满足先决条件后发生的事情。在 Eiffel 中,它们可以在方法或函数代码中与其他合约进行标点。将这些视为流程装配线上的 QA/QC 检查。
  • 命令(当)完成后,后置条件(则)必须成立。

故事的寓意

因为 BDD 只是用不同的词语重新包装的 DbC(霍尔逻辑),这意味着它不是 TDD。为什么?因为 TDD 并不是直接与方法、函数、属性和类状态相关的前置条件/​​检查/后置条件契约。 TDD 是测试方法、函数、属性和类及其离散状态的下一步。一旦您看到这一点并充分认识到 TDD 不是 BDD,BDD 也不是 TDD,而是它们是用于软件正确性证明的独立且互补的技术,那么您最终将正确理解这些主题。您还将正确使用和应用它们。

结论

Eiffel 是我所知道的唯一一种将 BDD(合同设计)原始融入到语言规范和编译器中的语言。它不是一个有局限性的弗兰肯斯坦怪物。在 Eiffel 中,BDD(又名 DbC)是软件正确性工具箱中优雅、有用、有用且直接的参与者。

另请参阅

维基百科帮助定义了霍尔逻辑。请参阅: https://en.wikipedia.org/wiki/Hoare_logic

我创建了一个示例在埃菲尔铁塔,你可以看看。请参阅:

主要类: https://github.com/ljr1981 /stack_overflow_answers/blob/main/src/so_73347395/so_73347395.e

测试类:https://github.com/ljr1981/stack_overflow_answers/blob/main/testing/so_73347395/so_73347395_test_set.e

Overall

BDD is really Design-by-Contract using different terms. Generally speaking, BDD is in the form of Given-When-Then, which is roughly analogous to Preconditions (Given), Check-conditions/Loop-invariants (When), and Post-conditions/Invariants (Then).

Notice

Note that BDD is very much Hoare-logic (i.e. {P}C{Q} or {P}recondition-[C]ommand-{Q}Post-condition). Therefore:

  • Preconditions (Given) must hold true for the command (method/function) to compute correctly. Any violation of the Given (precondition) signals a fault in the calling Client code.
  • Command(s) (When) are what happens after the precondition(s) are met. In Eiffel, they can be punctuated within the method or function code with other contracts. Think about these as though they are QA/QC checks along a process assembly line.
  • Post-conditions (Then) must hold true once the Command (When) is finished.

Moral of the Story

Because BDD is just DbC (Hoare-logic) repackaged in different words, this means it is not TDD. Why? Because TDD is not about preconditions/checks/post-condition contracts tied directly to methods, functions, properties, and class-state. TDD is the next step up the ladder in testing methods, functions, properties, and classes with their discrete states. Once you see this and fully appreciate that TDD is not BDD and BDD is not TDD, but that they are separate and complementary technologies for software correctness proofs—THEN—you will finally understand these topics correctly. You will also use and apply them correctly.

Conclusion

Eiffel is the only language I am aware of where BDD (Design-by-Contract) is baked raw into both the language specification and compiler. It is not a Frankenstein bolt-on monster with limitations. In Eiffel, BDD (aka DbC) is an elegant, helpful, useful, and direct participant in the software correctness toolbox.

See Also

Wikipedia helps defined Hoare-logic. See: https://en.wikipedia.org/wiki/Hoare_logic

I have created an example in Eiffel that you can look at. See:

Primary class: https://github.com/ljr1981/stack_overflow_answers/blob/main/src/so_73347395/so_73347395.e

Test class: https://github.com/ljr1981/stack_overflow_answers/blob/main/testing/so_73347395/so_73347395_test_set.e

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文