《Cucumber:行为驱动开发指南》——2.8 让测试通过

本节书摘来自异步社区《Cucumber:行为驱动开发指南》一书中的第2章,第2.8节,作者:【英】Matt Wynne , 【挪】Aslak Hellesy著,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.8 让测试通过

既然已经有了可靠的失败场景,那就是时候让这个Cucumber场景指导我们编写解决方案了。

有一个非常简单的方案能让测试通过,但该方案其实不会有实际的帮助,不管怎样我们先试一下,哪怕为了好玩儿:

下载first_taste/08/calc.rb
print "4"

试试运行cucumber,你会看到场景最终通过了:

...

1 scenario (1 passed)
3 steps (3 passed)
0m0.025s

很好!不过这个方案有什么问题呢?毕竟我们说过希望做能让测试通过的最少的工作,对不对?

事实上,这与我们之前说的不完全一样,我们说希望做能让测试通过的最少的、有用的工作。这里我们做的确实让测试通过了,但并不十分有用,暂且不说它根本没有计算器的功能这一事实,我们先看看这行耍小聪明的代码在测试时漏掉了什么。

  •  我们没有尝试从命令行读取输入。
  •  我们没有尝试做加法运算。
    在《Crystal Clear:小团队的敏捷开发方法》[Coc04]一书中,Alistair Cockburn提倡在项目中尽早构建一个可行走的骨架(walking skeleton),以便发现技术选型的任何潜在问题。显然我们的计算器非常简单,但一样值得我们考虑一下这条原则:为什么我们不构建一种能通过该场景的更有用的东西,并且让它帮助我们更多地了解自己打算使用的实现呢?

如果你不能信服这种观点,可以尝试将这种解决方案看成一个代码重复的问题。我们在两个地方硬编码了4这个值:一处是场景中,另一处是计算器程序中。在更复杂的系统中,类似的重复可能不会被注意到,因而使场景变得脆弱。

让我们强迫自己修复这个问题,可以使用Kent Beck在《测试驱动开发》一书中所说的三角法(triangulation)。我们使用一个新的名为Scenario Outline(场景轮廓)的关键字来为特性添加另一个场景:

下载first_taste/09/features/adding.feature
Feature: Adding

Joe问:我觉得很怪异,你一直在让测试通过但毫无作用!

我们实现了一个步骤,它调用了计算器程序然后就通过了,即便这个时候“计算器”还只是一个空文件。这到底是怎么回事?

记住一个步骤本身并不是一个测试,测试是整个场景,除非所有步骤都通过了,否则场景不可能通过。在我们实现所有步骤之后,只有一种办法能让整个场景通过,那就是构建一个能运行加法运算的计算器!

像这样由外向内工作的时候,我们常常会使用空计算器程序这样的桩(stub),把它作为一个将来需要填充的预留区域。我们知道不可能永远把空文件留在那里并侥幸成功,因为最终Cucumber会告诉我们,要让整个场景通过就必须回来给空文件夹添加内容,使它能做点有用的事。

故意只做能让测试通过的最少的、有用的工作,这一原则看起来很懒,但实际上是一条纪律,它能保证我们的测试彻底且周密:如果测试没有驱动我们编写正确的软件,那么我们就需要更好的测试。

Scenario Outline: Add two numbers 
 Given the input "<input>"

 When the calculator is run

 Then the output should be "<output>"

 Examples:
  | input | output | 
  | 2+2  | 4   | 
  | 98+1 | 99   |

我们把场景转变成了场景轮廓,这使我们可以用表格指定多个场景。另一种方法是复制并粘贴原来的整个场景然后改变其中的一些值,但我们认为使用场景轮廓在表述实例方面可读性更强,并且我们想让你体验一下Gherkin语法允许的其他写法。我们看一下现在输出是什么样子:

$ cucumber

Feature: Adding

 Scenario Outline: Add two numbers   
  Given the input "<input>"      
  When the calculator is run      
  Then the output should be "<output>" 

  Examples: 
   | input | output |
   | 2+2  | 4    |
   | 98+1  | 99   |
   expected: "99"
      got: "4" (using ==) (RSpec::Expectations::ExpectationNotMetError)
   ./features/step_definitions/calculator_steps.rb:15
   features/adding.feature:6

Failing Scenarios:
cucumber features/adding.feature:3 # Scenario: Add two numbers
2 scenarios (1 failed, 1 passed)
6 steps (1 failed, 5 passed)
0m0.072s

从摘要中的 2 scenarios (1 failed, 1 passed),我们可以看到Cucumber已经运行了两个场景,Cucumber运行场景轮廓的时候,它会把实例(Examples)表中的每一行扩展成一个场景。第一个实例(结果为4的那个)仍然通过了,但是第二个实例失败了。

现在,肯定应该用一个更切实的解决方案重新实现我们的程序了:

下载first_taste/10/calc.rb
print eval(ARGV[0])

首先我们读取命令行参数ARGV[0],然后把它传给Ruby的eval方法。这足以算出与计算器输入相关的结果,最后我们将结果打印到终端。

试一下,是不是两个场景都通过了?很好!你已经构建了自己的第一个用Cucumber驱动的应用程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值