第3章 描述需求 《RSpec手册》
为了提供一个合适的例子来实践RSpec和Cucumber的BDD开发,我们开始设计一个游戏,名为密码破译
。我们的游戏版本是基于命令行的。这个游戏源于使用铅笔在纸上玩的公牛和母牛
的游戏。
我们选择游戏来做实例,是因为它比银行或社交网络的应用更有趣一些。
先来看一下需求吧。
介绍游戏规则
这是一个逻辑熟悉,破译者要破译code-maker
生成的密码。code-maker
就是我们要写的应用,它从1到6之间任选四个数字作为密码。
然后破译者获取几次猜测的机会,每次可以猜测四个数字(还是1到6之间)。然后code-maker
会给出猜测结果,最多四个字符,每个字符可能是+
或-
。
+
表示猜中,即所猜测的数字存在并且位置也正确;-
表示虽然猜中了数字,但位置不正确。
例如,密码是1234
,一个猜测是4256
,那么可以得到+-
。+
表示2这个数字存在而且位置准确。而-
表示4这个数字虽然存在,但位置不正确。
符号+
总是显示在-
前面,并且也不需要跟密码中的位置对其。
计划发布的首个版本
正如后面章节还要讲到的,BDD的精神是Enough is enough
,遵守这个原则,会让开发的方向始终朝正确方向前进。
第一个版本,要简单一点。我们输入一个命令让游戏开始,然后提交猜测的答案、获得每轮猜测的结果,直到破译密码。这只是一个简化版,有很多遗留问题,但是一个简洁而具体的目标,让我们直到如何尽快开始工作。
选择用户故事
开始分析需求时,这里有一些备选的用户故事:
- 破译者开始游戏
- 破译者提交猜想
- 破译者成功了
- 破译者失败了
- 破译者重新玩一次
- 破译者要求提示
- 破译者获得了分数
需求最好用角色
+动作
这样的句式,但这个例子比较简单,只有破译者一个角色。其他应用中可能会有很多种用户,那就需要使用组的方式来表述实例。
提炼用户故事
- 破译者开始游戏: 破译者执行命令,看到欢迎信息和第一次猜测密码的提示。
- 破译者提交猜想: 破译者输入一个猜想,系统根据规则提示猜测的结果。
- 破译者成功了:
破译者输入猜想并且完全匹配的密码。系统提示
++++
,并给出祝贺信息和破译密码的次数。 - 破译者失败了: 在猜测一定次数之后,游戏告诉破译者“游戏结束”(需要决定多少次并更新密码)
- 破译者重新玩一次: 当游戏结束(破译成功或失败),系统提示破译者重新玩一次。如果破译者输入yes继续,就开始新的游戏。如果破译者输入no,游戏就关闭。
- 破译者要求提示: 在游戏的任何时间里,破译者都可以要求获得提示,即指出密码的某个数字。
- 破译者获得了分数: 游戏结束后,破译者可以保存信息:谁(初始化?),猜测了几次,是否成功,,等等。
缩窄用户故事范围
首先,必须的用户故事包括:
- 破译者开始游戏
- 破译者提交猜想
事实上,使用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 | ---- |