BDD, Behaviour-Driven Development
行为驱动开发
from the outside in
从外到里的开发方式。
Enough is enough
足够就足够了,就是不要太多,够用就可以了
avoid the pitfalls of the Big Design Up Front.
避免进入预先大设计的陷阱
user stories
用户故事,和user case有点相似
interation
迭代
first release
第一个版本
一个小游戏
系统给出四个数字,用户是看不到的,然后用户输入自己猜想的四个数字,显示四个+号就算赢,否则就是输了。
如果用户输入的数字在系统给出的四个数字之中,然后判断位置是否匹配,如果位置也匹配会显示一个+号,如果位置匹配的会显示一个-号。如果用户输入的数字不在系统给出的数字之中,就什么都不显示。
selecting stories
code-breaker start game.
code-breaker submits guess.
code-breaker wins game.
code-breaker loses game.
code-breaker plays again.
code-breaker requests hint.
code-breaker saves score.
使用周期迭代interation来开发我们的这个产品,每个周期我们放出一个release,一个可以执行的release。
首先我们设计一个目标作为当前interation的目标,也作为当前interation的结果。
避免把所有的事情都加入一个周期,避免预先(过渡)设计,避免一步到位,避免无休止的扩充。
每当想要扩充我们的interation的时候,考虑一下我们的interation目标,不要远离它,禁止无休止的扩充interation的内容。
要保证interation的时间不要太长,一般两周比较合适,也不能太短,否则一个feature都还没有完成。这个需要根据目标来指定interation的长短,所以目标也要比较合适才行,过大过小都会有问题。不要想一口吃个胖子,目标要分解,逐步实现。
ATDP, Acceptance Test-Driven Planning
ATDD, Acceptance Test-Driven Development
ATDD指明我们应该在写代码之前,先写可接受的测试,但是ATDD没有说明我们什么时候开始写。
ATDP指明可接受测试应该在interation计划会议上,或者在计划会议之前,就应该被确定下来,而不是在计划会议之后。迫使我们考虑验收准则,改进我们计划interation的能力,这就是为什么被叫做ATDP。
Cucumber用文本的格式描述应用的feature。包含三个部分:标题,一个简洁的描述,任意数量的scenarios作为验收准则。
- Feature: code-breaker starts game
- As a code-breaker
- I want to start a game
- So that I can break the code
- Scenario: start name
- Give I am nto yet playing
- When I start a new game
- Then I should see "Welcome to Codebreaker!"
- And I should see "Enter guess:"
- But I should not see "What is your question?"
在scenario后面有一个简单的描述,然后下面是一系列的步骤,每个步骤都以五个关键字中的一个开头:Given, When, Then, And, But.
Given代表事件发生之前,When代表事件,Then代表事件发生之后的预期结果。
And和But是对前一个步骤的补充说明,也就是另外一个Then。
- mkdir codebreaker
- cd codebreaker/
- mkdir features
- vi features/codebreaker_start_game.feature
在文件中敲入我们上面准备好的内容。
- mkdir -p features/support
- vi features/support/env.rb
- cucumber
来继续我们的第二个feature,submit a guess。
因为这个feature较前一个复杂,我们的描述也会是另外一种格式。
- Feature: code-breaker submits guess
- The code-breaker submits a guess of four numbers. The game mark the guess with + and - signs.
- For each number in the guess that matchs the number and position of a number in the secret code, the mark includes one +. For each number in the guess that matchs the number but not the position of a number in the secret code, a - is added to the mark.
- Scenario: all exact matches
- Given the secret code is "1234"
- When I guess "12345"
- Then the mark shoud be "++++"
由于这个地方会有一个算法,我们想要测试多种情况,来保证这个算法的正确性。可以添加多个scenario来实现。
- Scenario: all exact matches
- Given the secret code is "1234"
- When I guess "1234"
- Then the mark should be "++++"
- Scenario: 2 exact matches and 2 number matches
- Given the secret code is "1234"
- When I guess "1243"
- Then the mark should be "++--"
- Scenario: 1 exact matches and 3 number matches
- Given the secret code is "1234"
- When I guess "1243"
- Then the mark should be "+---"
- Scenario: 4 number matches
- Given the secret code is "1234"
- When I guess "4321"
- Then the mark should be "----"
但是上面的scenarioes开起来很费力,因为有大量的重复,真正想要的测试数据被淹没了。
Cucumber给我们提供了另外一种方式,Scenario Outlines。
- Scenario Outline: submit guess
- Given the secret code is "<code>"
- When I guess "<guess>"
- Then the mark should be "<mark>"
用scenario outline替代scenario,同时提供<>来保存变量。
- Scenarios: all numbers correct
- | code | guess | mark |
- | 1234 | 1234 | ++++ |
- | 1234 | 1243 | ++-- |
- | 1234 | 1423 | +--- |
- | 1234 | 4321 | ---- |
完整的feature描述如下
- Feature: code-breaker submits guess
- The code-breaker submits a guess of four numbers. The game mark the guess with + and - signs.
- For each number in the guess that matchs the number and position of a number in the secret code, the mark includes one +. For each number in the guess that matchs the number but not the position of a number in the secret code, a - is added to the mark.
- Scenario Outline: submit guess
- Given the secret code is "<code>"
- When I guess "<guess>"
- Then the mark should be "<mark>"
- Scenarios: no matches
- | code | guess | mark |
- | 1234 | 5577 | |
- | 1234 | 8697 | |
- Scenarios: 1 number correct
- | code | guess | mark |
- | 1234 | 1888 | + |
- | 1234 | 5488 | + |
- Scenarios: 2 numbers correct
- | code | guess | mark |
- | 1234 | 1278 | ++ |
- | 1234 | 1498 | +- |
- | 1234 | 7723 | -- |
- Scenarios: 3 numbers correct
- | code | guess | mark |
- | 1234 | 6234 | +++ |
- | 1234 | 1298 | ++- |
- | 1234 | 1723 | +-- |
- | 1234 | 7123 | --- |
- Scenarios: all numbers correct
- | code | guess | mark |
- | 1234 | 1234 | ++++ |
- | 1234 | 1243 | ++-- |
- | 1234 | 1423 | +--- |
- | 1234 | 4321 | ---- |
总结
缩小用户故事的范围,保证留下的用户故事和一次发布的目标匹配即可。
为一个interation选择用户故事,不要再一个interation中放入太多的用户故事,不要希望一个interation来完成所有的用户故事。
验收准则,我们通过写cucumber feature来描述用户故事。我们在迭代计划会议期间做这件事,使用这些来确定和修改我们的预估。
scenario outline,使得我们减少大量的重复,更加的DRY。
教程参考:The RSpec Book
所有的代码放在
https://github.com/woaigithub/the-rspec-book-with-cucumber