确定 BDD 场景中适当的详细程度

RHa*_*ris 3 bdd

我是 BDD 新手,并尝试使用它来充实新项目的功能规范。

您在网上看到的大多数示例在细节方面似乎都非常简单且轻松。我很难知道场景中应该包含哪些内容以及不应该包含哪些内容。

例如,给定如下标题:用户登录

场景 1:用户使用有效凭据登录

鉴于显示登录页面

用户输入用户名和密码时

并且用户提交请求

然后用户将被定向到主页

我不明白的是,如果用户被管理员禁用或由于密码尝试失败次数过多而被锁定,该怎么办?这些是单独的情况吗?如果是,场景 1是否需要表明该用户未被禁用且未被锁定

后端发生的事情怎么样——即客户端希望系统记录每个用户的登录——这是否包含在场景中?我读过的大多数内容听起来好像 BDD 应该专注于用户与系统的交互。

如果您确实包含诸如登录后端之类的内容,那么在登录尝试失败时增加失败登录计数器之类的内容又如何呢?这看起来更像是一个技术细节——那么如果需要锁定功能,它在哪里记录呢?

正如您所看到的,我很难决定在 BDD 场景的范围方面划清界限。

感谢您帮助更好地理解!

Lun*_*ore 5

我们应该在场景中包含哪些上下文?

我发现将场景视为有助于说明系统行为方式及其价值的实时文档,而不是测试,这会有所帮助。

如果您可以判断用户在第一种情况下没有被锁定并且没有被禁用,那么您不需要包括这些步骤。

对于使用活跃的、已启用的帐户登录之类的情况来说,这是显而易见的,但对于交易者保持在其交易限制内,或者以健康的速度运行的胎儿心跳,或者尚未达到的评论之类的情况,这可能不是报告阈值。您可以实际地决定是否包含此类上下文。

不过,我更喜欢将不更改或不经常更改的文档(例如核心领域概念)移至场景之外。也许它可以位于场景文件顶部的简介中,或者位于团队 wiki 上,新加入者在编码之前可以阅读。它不一定是在场景中。

(显然,您需要包含在任何失败场景中导致失败的上下文!)

副作用和其他结果怎么样?

所有重要的结果之所以如此,是因为在某些时候,它们变得可见或产生超出场景中行为所涵盖的系统的影响。

例如,当我从提款机取钱时,我的账户也会被扣除。我可能不认为这是行为的一部分,但它确实必须发生。这是因为该场景还涉及另一个利益相关者——银行。

或者,当弗雷德获得微波炉退款时,微波炉会重新入库,并且库存数量会增加。Fred、收银员和库存控制员都是这里的利益相关者。

在我们向日志添加某些内容的情况下,有一个利益相关者会将这些日志用于其他用途。意识到该价值可以帮助我们弄清楚为什么要记录日志,并从认为它有价值的利益相关者的角度描述该结果。

如果结果可以独立交付并且仍然有价值,那么它们可以出现在不同的场景中。我对此非常务实,所以我可能会将它们放在同一个场景中,然后在“库存控制”场景的数量意味着它可能应该有自己的功能文件时重构它们。

如果结果不能独立交付(任何交易通常都是这种情况),我希望看到这些结果在至少一种情况下一起出现,以表明它们是相关的。它们不必出现在每个场景中。例如,一旦我们编写了用户没有资金,因此他们的帐户不会被扣款的场景,我们可能就不必在任何其他提现失败场景中再次提及该帐户。

多个利益相关者的这种视角也与“从外到内”的 BDD 概念相关,其中我们添加到系统中的所有行为都是为了通过某些接口为某些利益相关者提供价值。

与其他用户或时间的互动怎么样?

有时 - 非常偶尔 - 我们需要多个时间描述正在发生的事情,并且登录计数器递增的示例是一个很好的使用示例。

登录计数器的值只是在 3 次尝试后(例如)禁用该帐户。它本身没有任何价值。这是一个实施细节。如果我们将其变成场景中的结果,我们就会将自己与该实现耦合起来,这并不是很好。因此,有两种场景 - 一种描述登录计数器如何工作,另一种显示它为何有价值 - 感觉不对,因为其中一种没有描述有价值的行为:

Given Clarence logged in successfully last time
When Clarence enters his password incorrectly
Then the login counter should be incremented.

Given Clarence's login counter was incremented twice
When Clarence enters his password incorrectly
Then his account should be disabled.
Run Code Online (Sandbox Code Playgroud)

哎呀。我们不要那样做。

该计数器中的唯一值来自克拉伦斯的行为与克拉伦斯未来(或过去)的行为的相互作用。所以我们可以有这样的东西:

Given Clarence logged in successfully last time
When he enters his password incorrectly
And enters his password incorrectly
And enters his password incorrectly
Then his account should be disabled.
Run Code Online (Sandbox Code Playgroud)

当然,这有点拗口,所以我们可能会说:

Given Clarence logged in successfully last time
When he enters his password incorrectly 3 times
Then his account should be disabled.
Run Code Online (Sandbox Code Playgroud)

我们可以做到这一点,因为同样的事情正在发生。但有些互动涉及不同的事情发生(“时间流逝”是我经常遇到的另一种互动)。

Given Clare is editing trade 12345
When Stephen edits and saves that trade
And Clare tries to save that trade
Then she should be told that Stephen has already edited it.
Run Code Online (Sandbox Code Playgroud)

当然,在这种情况下,克莱尔的互动与斯蒂芬的互动不同,因为她的拯救尝试失败了。

注意这里使用try来表示失败;我如何使用假设的另一个例子。如果它没有说“尝试”,我们可以假设该事件已成功。另一种选择是:

When Clare saves the trade successfully
Run Code Online (Sandbox Code Playgroud)

除非成功的结果在某种程度上令人惊讶而不是常态,否则这会有点重复,所以我更喜欢默认不使用任何内容并尝试失败。从自动化的角度来看,它们之间的区别很重要,因为它可以让我们做一些事情,例如将自动化工作流程移至错误页面而不是确认页面。

它读起来也很好看。这就是我们尝试使用这些英语语言工具的原因。