这些天我读过几篇关于BDD
的文章,以找到它所说的内容。现在我得到了一个基本的理解,但仍然不清楚整个过程。
所有利益相关者(BA,客户,Dev,QA)都坐在一起讨论要求,并在故事卡上写下商定的功能。在这里,我以“用户注册”功能为例:
As a user,
I want to register on the system,
so that I can use its services
以Given/When/Then
格式创建多个方案,其中之一是:
Scenario: user successfully register
Given an register page
And an un-registered user
When the user fills username "Jeff" and password "123456"
And click on "Register"
Then the user can see a "Success" message
And the user "Jeff" is created in the system
使用某些BDD测试框架实现此方案,例如cucumber-jvm,如:
import cucumber.api.java.en.Given;
public class Stepdefs {
@Given("an register page")
public void an_register_page throws Throwable {
// ...
}
@Given("an un-registered user")
public void an_register_page throws Throwable {
// ...
}
// ...
}
逐步完成步骤。
但我很快发现自己陷入困境:这个场景中有页面,模型,数据库需要,似乎有很多事情要做。
我现在该怎么办?我是否需要与所有利益相关方讨论这种情况?对于BA/Customer/QA
,我认为他们并不真正关心实现,与其他开发人员讨论它是否是一个好主意?
假设在与其他开发人员讨论之后,我们同意将其拆分为几个小部分。我们可以使用Scenario/Given/When/Then
格式将这些小部分作为我们刚刚使用cucumber-jvm进行的“方案”,或者我们可以像通常在TDD中那样使用JUnit吗?
1. If choose "cucumber-jvm", it seems a little heavy for small part
2. If choose JUnit, we need to involve more than one testing framework in a project
3. Is it the best if there is a single testing framework to do both things (not sure if there is)
假设我选择选项2
,使用JUnit执行小任务
以下是我在做出这个决定后会做的事情:
现在我们创建新的小测试来驱动实现,比如在数据库中创建用户,就像我们通常在TDD中那样。 (红 - >绿光>重构)。我们现在不关心黄瓜测试Scenario: user successfully register
(失败了),只要把它放在那里。右
我们用JUnit开发了更多小测试,使它们变红 - >绿色 - >重构。 (并且不完整的黄瓜测试总是失败)
在通过所有小测试之前,我们转向黄瓜测试Scenario: user successfully register
。完成它并确保它最后变绿。
现在开发另一个场景,如果它很容易,我们可以用黄瓜实现它,否则我们将不得不拆分并写几个jUnit测试
肯定存在许多误解,甚至是非常基本的误解。因为除了“与所有利益相关者讨论”之外,我发现自己从BDD中获得了很多价值。
我的错误在哪里?感谢任何建议!
答案 0 :(得分:2)
不要先登录;从那些与其他系统不同的东西开始。为什么有人登录?他们为什么要使用这项服务?对用户进行硬编码,假装他们已经登录,专注于该值。
如果您专注于UI细节,则会非常强烈地将自己绑定到UI,这会使UI难以更改。相反,看看系统提供的功能。我不建议使用登录方案,但如果我这样做,我希望它看起来更像:
Given Jeff isn't registered with the site
When he registers with the username "Jeff" and password "123456"
Then his account creation should be confirmed
And he should be invited to log in for the first time.
查找"声明与命令"在这里可以看到更多。
如果您的用户界面真的不稳定,请手动试用该方案,直到用户界面稍微稳定下来。那么自动化会更容易。当您进入更稳定的场景时,首先自动化(TDD风格)会更好。
你现在应该怎么做?好吧,大多数人都没有为UI编写类级别的测试,所以在你开始驱逐控制器和演示者层之前不要担心。使用相同语言的框架通常更容易,但两个不同的框架是可以的。 Cucumber / RSpec,JBehave / JUnit,SpecFlow / NUnit是非常典型的组合。做第一个场景工作所需的最小量。它不会很多,因为你可以硬编码很多。第二种情况将开始引入更有趣的行为,然后您将开始看到您的类级别测试出现。
是的,你的黄瓜情景一直都是红色,直到它没有。
理想情况下,您将进行最后一次单元测试并同时传递Cucumber场景,而不仅仅是编写一些额外的代码。看到它最终走向绿色非常令人满意。
BDD的最初目的是摆脱" test"这个词,因为它会让人们认为像TDD这样的东西是关于测试的。 TDD真正关注清洁设计;了解代码的职责和行为,就像方案可以帮助您了解系统的功能和行为一样。编写系统级场景和类级别测试也应该是正常的。
但是,您已经领先于所有在开始编码之前忘记讨论方案的人!与利益相关者的对话是最重要的部分。在这些对话中包括测试人员可能会获得价值。测试人员非常擅长发现其他人错过的场景。
看起来你几乎在正确的轨道上进行了其余的处理。您可能会在我的个人资料中发现其他一些BDD答案对您也有帮助。恭喜,祝你好运!
答案 1 :(得分:2)
我认为在学习BDD的机制时,首先进行注册/ sign_in是一件非常好的事情。几乎每个人都明白为什么你想要登录系统,每个人都明白系统必须知道你是谁才能做到这一点,所以你必须先注册。
执行此简单任务可以让您专注于较小的BDD子集。通过缩小你的注意力,你可以提高质量,同时意识到稍后可以学到更多东西。
要编写您的登录方案,您需要关注两件事:
这些是BDD的基本机制,但它们只是整个过程的一小部分。我仍然认为你可以从中受益,因为目前你并没有很好地执行这些机制,这是因为你不熟悉这一点。
当你编写场景时,你应该专注于你正在做什么以及'为什么'你这样做。情景无需了解“你如何”做事。填写东西,点击东西等任何事情都是一种气味。当你的场景只处理它们变得更简单的原因和原因时。
Feature: Registration
A pre-requistite for signing in, see sign_in.feature
Scenario: Register
Given I am a new user
When I register
Then I should be registered
Feature: Sign in
Dependant on registration ...
I want to sign in so I can have personalised content and ...
Scenario: Sign in
Given I am registered
When I sign in
Then I should be signed in
你真的没有比这更能推动简单的sign_in系统的开发了。一旦你运行了,你可以处理一些悲伤的道路,例如。
Scenario: Sign in with bad password
Given I am registered
When I sign in with a bad password
Then I should not be signed in
And I should be told ...
如果你实现得很好,这个悲伤的路径场景应该是微不足道的,因为所有的基础设施已经到位登录,所有不同的是你使用的是错误的密码。
您可以在https://github.com/diabolo/cuke_up查看此示例。使用此示例的方法是遵循提交历史记录,特别注意我如何使用extract_method重构来从步骤定义中获取所有代码。我提取的每个方法都是在编写后续场景时重用的工具。在实施方案时,制作一套有效的工具是提高工作效率的关键。
Nowadys sign_up非常简单,因为我们可以依赖第三方库及其单元测试。这意味着我们可以获得相当不错的结果,而无需担心过渡到我们自己的代码和做一些TDD。所以现在真的没有必要考虑TDD。
只要您知道自己只是做了BDD的一小部分,我认为您可以成功地使用这种方法为处理区分系统的事情时需要处理的所有额外内容提供基础。来自其他人。
总结一下,只关注
你有足够的时间学习其他东西,如果你的基本机制得到更好的发展,那将会容易得多。