目录

为了提供一个合适的例子来实践RSpec和Cucumber的BDD开发,我们开始设计一个游戏,名为密码破译。我们的游戏版本是基于命令行的。这个游戏源于使用铅笔在纸上玩的公牛和母牛的游戏。

我们选择游戏来做实例,是因为它比银行或社交网络的应用更有趣一些。

先来看一下需求吧。

介绍游戏规则

这是一个逻辑熟悉,破译者要破译code-maker生成的密码。code-maker就是我们要写的应用,它从1到6之间任选四个数字作为密码。

然后破译者获取几次猜测的机会,每次可以猜测四个数字(还是1到6之间)。然后code-maker会给出猜测结果,最多四个字符,每个字符可能是+-

+表示猜中,即所猜测的数字存在并且位置也正确;-表示虽然猜中了数字,但位置不正确。

例如,密码是1234,一个猜测是4256,那么可以得到+-+表示2这个数字存在而且位置准确。而-表示4这个数字虽然存在,但位置不正确。

符号+总是显示在-前面,并且也不需要跟密码中的位置对其。

计划发布的首个版本

正如后面章节还要讲到的,BDD的精神是Enough is enough,遵守这个原则,会让开发的方向始终朝正确方向前进。

第一个版本,要简单一点。我们输入一个命令让游戏开始,然后提交猜测的答案、获得每轮猜测的结果,直到破译密码。这只是一个简化版,有很多遗留问题,但是一个简洁而具体的目标,让我们直到如何尽快开始工作。

选择用户故事

开始分析需求时,这里有一些备选的用户故事:

  • 破译者开始游戏
  • 破译者提交猜想
  • 破译者成功了
  • 破译者失败了
  • 破译者重新玩一次
  • 破译者要求提示
  • 破译者获得了分数

需求最好用角色+动作这样的句式,但这个例子比较简单,只有破译者一个角色。其他应用中可能会有很多种用户,那就需要使用组的方式来表述实例。

提炼用户故事

  1. 破译者开始游戏: 破译者执行命令,看到欢迎信息和第一次猜测密码的提示。
  2. 破译者提交猜想: 破译者输入一个猜想,系统根据规则提示猜测的结果。
  3. 破译者成功了: 破译者输入猜想并且完全匹配的密码。系统提示++++,并给出祝贺信息和破译密码的次数。
  4. 破译者失败了: 在猜测一定次数之后,游戏告诉破译者“游戏结束”(需要决定多少次并更新密码)
  5. 破译者重新玩一次: 当游戏结束(破译成功或失败),系统提示破译者重新玩一次。如果破译者输入yes继续,就开始新的游戏。如果破译者输入no,游戏就关闭。
  6. 破译者要求提示: 在游戏的任何时间里,破译者都可以要求获得提示,即指出密码的某个数字。
  7. 破译者获得了分数: 游戏结束后,破译者可以保存信息:谁(初始化?),猜测了几次,是否成功,,等等。

缩窄用户故事范围

首先,必须的用户故事包括:

  • 破译者开始游戏
  • 破译者提交猜想

事实上,使用Ctrl+C终止程序,然后重新启动程序也是可以重新玩的,但这么做体验不太好。最终的故事范围可以这样定:

  • 破译者开始游戏
  • 破译者提交猜想
  • 破译者成功了
  • 破译者重新玩一次

也许有人想把上面列的8个故事全部用上,这注意或许不错。但是别忘了,我们这次迭代的任务是什么,是“简洁”,能够运行起来,上面四个故事的范围已经足够了。

隐藏的用户故事

想到了吗?对,是密码生成。

  • code-maker生成密码

这究竟算不算一个独立的用户故事?事实上,这是一个灰色地带,你可以把它当作一个独立的用户故事,也可以作为其他故事的一部分(例如开始游戏的时候就该生成密码)。

用户故事是计划的工具

设计用户故事三原则:

  • 有商业价值
  • 可测试
  • 足够小,可以在一次迭代中实现

计划第一次迭代

Cucumber让我们在简单的纯文本中描述应用功能,然后自动化执行。我们在本章中描述应用功能,然后再下一章完成自动化执行。

叙述功能

Cucumber功能有三部分:标题、描述和提供测试标准的场景。就如下面的例子:

#languague: zh-CN
功能: 破译者开始玩游戏

  作为一个破译者
  我要开始游戏
  去破译密码

验收标准

我们在功能中增加了验收标准。想象一下你作为破译者坐下来玩这个游戏,首先打开shell,然后敲入codebreaker的命令。你会直到怎么开始玩吗?可能要先来一行“欢迎来玩'密码破译'游戏”的欢迎词,然后如你所想的再出现一句“请从1-6的数字中选择4个作为猜想答案”。

#languague: zh-CN
功能: 破译者开始玩游戏

  作为一个破译者
  我要开始游戏
  去破译密码

  场景: 开始游戏
    假如我还没开始
    当我开始新的游戏
    那么我应当看到"欢迎来玩破译密码的游戏!"这样的欢迎辞
    并且我应当看到"请从1-6的数字中选择4个作为猜想答案:"的提示

提交答案

#language: zh-CN
功能: 破译者提交答案

  破译者从1-6中选择四个数字作为猜想答案。
  游戏会反馈猜想结果:+和-。

  答案中的每个数字若在密码中存在,并且位置准确就返回一个+;若仅存在数字但位置不准确就返回一个-。

  场景大纲: 猜想匹配测试
    假如密码是"<code>"
    当我提交"<guess>"
    那么我应当得到的反馈是"<mark>"

    例子: 没有匹配
    | code | guess | mark |
    | 1234 | 5555  |      |

    例子: 1个数字正确
    | code | guess | mark |
    | 1234 | 1555  | +    |
    | 1234 | 2555  | -    |

    例子: 2个数字正确
    | code | guess | mark |
    | 1234 | 5254  | ++   |
    | 1234 | 5154  | +-   |
    | 1234 | 2545  | --   |

    例子: 3个数字正确
    | code | guess | mark |
    | 1234 | 5234  | +++  |
    | 1234 | 5134  | ++-  |
    | 1234 | 5124  | +--  |
    | 1234 | 5123  | ---  |

    例子: 全部正确
    | code | guess | mark |
    | 1234 | 1234  | ++++ |
    | 1234 | 1243  | ++-- |
    | 1234 | 1423  | +--- |
    | 1234 | 4321  | ---- |