原文是为《PHPer》电子杂志写的一篇稿子,这里摘取了一部分(主要是代码)发表。
BDD(行为驱动开发)是很热门的话题。对于热门话题我都是有好奇心的 ^_^
仔细看了一下各种资料,发现 BDD 真是个好东西。
以前写测试,都是针对功能来写测试。而 BDD 是针对系统行为的来写测试,实际上就是用测试定义了系统的行为。这样一来,写测试的过程实际上就是“设计”。在设计系统各个子系统应该具有的功能,这些功能的行为等等。
所以 BDD 是一种完完全全的设计方法,而不是测试方法(其实 TDD 也可以算是设计方法,不过争议很大)。
好了,理论性的东西不多说了,先看看一个实际的“故事”和其测试代码。
故事“帐户持有人提取现金”及场景“帐户有足够的资金”:
Story: 帐户持有人提取现金
As an [帐户持有人]
I want [从 ATM 提取现金]
So that [可以在银行关门后取到钱]
Scenario 1: 帐户有足够的资金
Given [帐户余额为 $100]
And [有效的银行卡]
And [提款机有足够现金]
When [帐户持有人要求取款 $20]
Then [提款机应该分发 $20]
And [帐户余额应该为 $80]
And [应该退还银行卡]
看上去很容易理解吧 :)
下面是测试代码:
-
<?php
-
-
require_once'PHPUnit/Extensions/Story/TestCase.php';
-
-
/**
-
* 测试从账户中取现
-
*/
-
classAccountHolderWithdrawsCashSpec extends PHPUnit_Extensions_Story_TestCase
-
{
-
/**
-
* @scenario
-
* 场景 1: 帐户有足够的资金
-
*/
-
functionAccountHasSufficientFunds()
-
{
-
$this->given('帐户余额为', 100)
-
->and('有效的银行卡')
-
->and('提款机有足够现金')
-
->when('帐户持有人要求取款', 20)
-
->then('提款机应该分发', 20)
-
->and('帐户余额应该为', 80)
-
->and('应该退还银行卡');
-
}
-
-
// ...
-
-
/**
-
* 处理 given
-
*/
-
functionrunGiven(&$world, $action, $arguments)
-
{
-
switch($action)
-
{
-
case'帐户余额为':
-
// 由于 Account 对象必须属于一个 AccountHolder(帐户持有人),
-
// 因此需要构造一个 AccountHolder 对象
-
$account_holder = newAccountHolder();
-
$account_holder->name = 'tester';
-
// 创建一个 Account 对象,并设置余额为 $arguments[0]
-
$world['account'] = newAccount($account_holder);
-
$world['account']->balance = $arguments[0];
-
break;
-
-
case'有效的银行卡':
-
$card = newCreditCard($world['account']);
-
$card->valid = true;
-
$world['card'] = $card;
-
break;
-
-
case'提款机有足够现金':
-
// 确保 ATM 的余额大于帐户余额
-
$world['atm'] = newATM();
-
$world['atm']->balance = $world['account']->balance + 1;
-
break;
-
-
default:
-
{
-
return$this->notImplemented($action);
-
}
-
}
-
}
-
-
/**
-
* 处理 when
-
*/
-
functionrunWhen(&$world, $action, $arguments)
-
{
-
/**
-
* 在 when 中调用对象的业务方法
-
*/
-
switch($action)
-
{
-
case'帐户持有人要求取款':
-
// 从指定提款机使用指定银行卡取出现金
-
$world['account']->drawingByATM($world['atm'], $world['card'], $arguments[0]);
-
break;
-
-
default:
-
return$this->notImplemented($action);
-
}
-
}
-
-
/**
-
* 处理 then
-
*/
-
functionrunThen(&$world, $action, $arguments)
-
{
-
/**
-
* 在 then 中验证业务对象的状态是否符合标准
-
*/
-
switch($action)
-
{
-
case'提款机应该分发':
-
// 验证提款机的余额
-
$this->assertEquals($arguments[0], $world['atm']->last_dispense, "提款机应该分发 {$arguments[0]}");
-
break;
-
-
case'帐户余额应该为':
-
// 验证帐户余额
-
$this->assertEquals($arguments[0], $world['account']->balance, "帐户余额应该为 {$arguments[0]}");
-
break;
-
-
case'应该退还银行卡':
-
// 验证银行卡没有被 ATM 锁定
-
$this->assertTrue($world['card']->isCheckedOut(), '应该退还银行卡');
-
break;
-
-
default:
-
return$this->notImplemented($action);
-
}
-
}
- }
基本上测试代码就是从“故事”文本转换过来的。只不过 PHPUnit 对 BDD 的支持还不是很成熟,所以看上去有点别扭。
跑一下这个测试看看结果呢:
> phpunit –story AccountHolderWithdrawsCashSpec
PHPUnit 3.3.0beta1 by Sebastian Bergmann.
AccountHolderWithdrawsCashSpec
- Account has sufficient funds [failed]
Given 帐户余额为 100
and 有效的银行卡
and 提款机有足够现金
When 帐户持有人要求取款 20
Then 提款机应该分发 20
and 帐户余额应该为 80
and 应该退还银行卡
Scenarios: 1, Failed: 1, Skipped: 0, Incomplete: 0.
呵呵,测试失败哦。可惜 PHPUnit 3.3 beta 1 还没法显示具体是哪一个测试失败了,所以要去掉 –stroy 参数再运行一次测试:
> phpunit AccountHolderWithdrawsCashSpec
PHPUnit 3.3.0beta1 by Sebastian Bergmann.
F
Time: 0 seconds
There was 1 failure:
1) AccountHasSufficientFunds(AccountHolderWithdrawsCashSpec)
帐户余额应该为 120
Failed asserting that matches expected value .
D:/www/517sc/test/AccountHolderWithdrawsCashSpec.php:10080>120>
FAILURES!
Tests: 1, Assertions: 2, Failures: 1.
这样就很清楚了,原来是帐户余额测试没有通过。知道问题所在,解决起来就很简单了。
分享到:
相关推荐
我鼓励您尝试一下,并就您遇到的问题提供反馈。 使用 Github Issues 报告问题、反馈和提问。要求您需要一个 C++11 兼容编译器来使用 ZingBDD,因为它使用仅在那里可用的语言结构。 包含一个用于构建演示的 Xcode 5 ...
实例068 通过类的多态性确定人类的说话行为 第7章 异常处理和程序调试 实例069 使用try…catch语句捕获异常 实例070 根据实际年龄判断虚岁,使用try…catch捕获异常 实例071 调试程序执行时出现的结果 实例072 使用...
BadActor BadActor是一个基于fail2ban精神构建的内存中,应用程序驱动的狱卒。 一种主要目的是增加参与系统探测或攻击的“不良行为者”的支出的中间件。 BadActor BadActor BadActor是一种内存中的,由应用程序驱动...
BIOS还用于根据探测输入/输出(I/O)来发现系统设备和加载驱动程序,并尝试将正确的驱动程序匹配到正确的设备(即插即用)。设备的位置也可以在BIOS中硬编码,因为平台本身是不可枚举的。这些解决方案在三个关键方面存在...
� 源代码完全开放,便于开发人员更清楚的把握实现细节,便于提高开发人员的技术水平,有利于开发 出 更具差异性的应用。 � 采用了对有限内存、电池和 CPU 优化过的虚拟机 Dalvik , Android 的运行速度比想象的要...
注意:在尝试使用WDF时,可能会遇到未记录的行为或APIS。 我们强烈建议您不要依赖该行为,因为它在将来的版本中可能会发生变化。 使用框架进行调试 使用此存储库中的源代码,开发人员可以对WDF源代码执行逐步调试。...
我们使用与域驱动设计,行为驱动开发,事件风暴,用户故事映射紧密相关的技术。 域描述 公共图书馆允许顾客在其各个图书馆分支处搁置书籍。 在任何给定的时间点,只有一位顾客可以搁置可用的书籍。 书籍可以是流通...
在这项研究中,我们考虑了带有双面绝热壁的二维双盖驱动腔。 通过控制方程的集合数学地说明了这个问题,并且使用有限差分法(FDM)在数值上解决了开发的模型。 本研究的目的是从数值上分析热行为和参数对二维室内...
用法组织Meta Driver由两个组件组成:使用行为驱动的测试框架的驱动程序行为规范;以及以及符合规范的参考实现。 Cucumber文件位于features /目录中,并且实现在bson-ruby /子模块(BSON实现)和lib /目录(有线协议...
准备与比赛这是我正在开发的模拟,以探讨在不同情况下... 可以在游戏类上配置许多因素来改变情况(失败的成本、成功的回报、多元性等),并且存在创造不同行为倾向的玩家的能力(即更愿意尝试,或者对准备更感兴趣)。
测试驱动开发; 具有覆盖支持的单元测试; ; ; ; ; 变异测试; 确保高质量的单元测试 消费者驱动的合同测试; 确保独立的生产路径 集成测试; API文档; 从可靠的集成测试中提取的可靠文档; 静态分析; 确保来源无...
此示例代码与“行为驱动开发”和以Angular编写的Javascript应用程序相关。 它介绍了如何在Angular应用程序上通过Protractor和Cucumber.js执行Gherkin功能。安装安装过程需要Node.js,npm和Bower。 $ npm install$ ...
BDD Assistant 是一个开源项目,旨在促进行为驱动开发 (BDD) 故事的创建和执行,以此作为更好地定义需求的一种方式。 更多信息可以在。 软件仍处于早期阶段。 我们正在寻找早期采用者来帮助我们。 如果您有兴趣...
Devcards不是REPL,因为它是由源文件中存在的代码驱动的,但是它通过允许开发人员快速尝试不同的代码示例并查看它们在实际DOM中的行为来尝试提供类似于REPL的体验。 Devcards围绕卡片的概念而居中。 每张卡代表...
这使它能够查找和删除新的和正在开发的“零日”恶意软件,防病毒软件没有当前的检测签名。 启动前的保护 Rootkits深入嵌入操作系统以隐藏防病毒软件。这些rootkit可以感染主引导记录,允许它们在Windows操作系统...
BDD(行为驱动开发)后,我爱上了将您的需求放入自动化、可执行测试的想法。然而, 不清楚如何以一种与其他自动化测试很好地结合的方式使用 Angular、其他 SPA 框架或一般 JavaScript 项目来设置和实践 BDD。我研究了...
PaperTTY图像显示命令@ colin-nolan提供了一个子命令来在屏幕上显示图像文件,从而可以测试显示效果或轻松制作照片...请注意,现在默认行为是进行部分更新,如果要使用完整更新,则需要在驱动程序设置中添加--nopartial
(4)如果你想自己尝试设计一个操作系统,则先在一个提供源码级调试的软件仿真器上进行开发,可能会大大提高你的开发进度。 <br>对于想了解、学习一般操作系统的实现原理,Linux/μCLinux操作系统或TCP/IP等系统...
内容简介 本书将尝试帮助入门级、中级以及高级读者理解基本的分布式计算概念,并且展示 ...第 8 章 测试与设计:行为说明、领域驱动设计以及 Akka Testkit。 第 9 章 尾声:其他 Akka 特性。下一步需要学习的知识。
内容简介 本书将尝试帮助入门级、中级以及高级读者理解基本的分布式计算概念,并且展示 ...第 8 章 测试与设计:行为说明、领域驱动设计以及 Akka Testkit。 第 9 章 尾声:其他 Akka 特性。下一步需要学习的知识。