• 行为驱动开发BDD概要


    BDD脱胎于TDD

    行为驱动开发(Behavior-Driven Development,简称BDD),是在测试驱动开发(Test-Driven Development,TDD)基础上发展而来的一种软件开发方法。TDD最大的弊端,是面对一大堆的功能需求和用例时,往往会感到无从下手。另一方面,由于TDD更侧重于测试本身,因此容易忽视对业务需求的表达,最终沉溺于琐碎细节而无法自拔。

    TDD

    BDD避免了信息丢失

    与传统的软件开发方法相比,BDD的本质在于尽可能避免在需求描述、用例撰写、代码实现、测试等各环节衔接、转译过程中发生的信息丢失。为此,BDD以用例Use Case和示例Example为核心,借助Gherkin等一些特有概念和一系列BDD特有工具,以更贴近业务场景的方式,实现软件需求的完整实现。二者的比较如下图所示。

    Traditional circle

    传统软件开发

    BDD circle

    BDD开发

    BDD流程

    BDD的每个迭代可以表述为:

    • 规划整个系统,得到抽象的业务目标Business Goal
    • 将业务目标细化为若干个具体的功能需求Feature
    • 采取Given-When-Then三段式编写Gherkin,用具体的场景示例Example描述和演示特定的功能
    • 将Example转换为可执行的Specification
    • 将Specification再拆解为更低层次的、逼近代码实现的Low-Level Specification与测试Test
    • 从Low-Level Specification中得到代码实现,并析取活动文档Living Documentation

    BDD Activity

    发掘Business Goal与Feature

    采用Why-Who-How-What四步法发掘Business Goal

    • Why:出于何种原因要开发此系统?
    • Who:谁将从系统中受益?谁是系统的用户?谁会影响系统的开发?
    • How:怎样才能更便捷、更容易地达成业务目标?
    • What:系统能做哪些工作来实现业务目标?

    Why-Who-How-What

    而在从Business Goal发现Feature时,则采用了Why-Who-What-How四步法进行Feature的粒度细分,得到最终的用户故事。

    Feature

    其中,Capability是“用户需要能做什么”,而Feature是“软件能提供怎样的帮助”

    BDD工具

    在.NET平台,从Example到可执行的Specification,有SpecFlow可用;再到Low-Level Specification,有NUnit、RSpec等工具可用。

    BDD Tool

    .NET平台下的BDD开发

    在Visual Studio集成环境下,可以按以下步骤实施BDD。

    准备工作

    为Visual Studio安装SpecFlow扩展插件

    安装扩展后,将可以在项目中添加用于编写Gherkin的Feature文件

    Specflow for VS

    为项目添加SpecFlow支持包

    SpecFlow.NUnit集成了SpecFlow与NUnit,更方便我们编写相关的测试,所以选择安装它即可。如果要使用最新版本的SpecFlow与NUnit,则请分别选择安装(NUnit3.0与SpecFlow1.9.0貌似有冲突,测试无法被识别)。如果你喜欢其他的单元测试框架,请选择并安装相应类型的package。

    nuget

    撰写Gherkin

    Gherkin,是BDD中采取特定格式、用于描述特定的Feature、形式为特定业务场景示例Example的文本。它较之需求规范Specification更具体明了,有点类似Use Case,但更具体生动,且既可用作测试脚本,又可作为归档的内容。

    添加Gherkin

    为项目添加新项,选择“SpecFlow Feature File”

    New Item

    编辑Gherkin

    打开Feature文件,修改模板内容,得到具体业务需求的描述。其中Feature是功能描述(描述用的文本将自动作为SpecFlow测试的类名),Scenario是具体的业务场景(描述用的文本将自动作为SpecFlow测试名),接着是Given-When-Then的三段式Example描述(描述用的文本将自动作为SpecFlow生成的分步Step的方法名)。

    Gherkin

    生成可执行的Specification

    可执行的Specification,是用来确认业务需求规范是否已被正确实现的自动化测试方法。

    每一组Specification,对应Gherkin里的一个Given-When-Then的三段式场景Scenario。三段式的每一个分句,都将对应一个具体的测试方法,这被叫作分步Step。每个Step的方法骨架可借由SpecFlow等BDD工具自动生成,之后再手工修改即可。

    SpecFlow+NUnit的组合,可以很容易地编写出可测试的Step,在Gherkin文本里的Given-When-Then等关键字上点击右键,选择“Generate Step Definitions”即可。在Attribute里出现的(.*)是占位符,类似正则析取参数。

    Steps

    在Build项目后,我们打开单元测试窗口,即可发现SpecFlow测试的踪影。由于此时每个分步Step里并没有我们实际的代码,因此我们运行测试时,会提示Step尚未被实现。

    Unit Test Window

    为了让SpecFlow的测试真正动起来,还需要修改Step的实现。简单演示如下:

    新增Account类

    namespace BDDExercise
    {
    public class Account
    {
    public decimal Balance { get; set; }

    public void Withdraw(decimal amount)
    {
    if (Balance - amount >= 0)
    Balance -= amount;
    }

    public void Deposit(decimal amount)
    {
    if (amount > 0)
    Balance += amount;
    }

    public Account(decimal amount)
    {
    if (amount > 0)
    Balance = amount;
    }
    }
    }

    修改Step方法

    using NUnit.Framework;
    using TechTalk.SpecFlow;

    namespace BDDExercise
    {
    [Binding]
    public class TransferringMoneyBetweenAccountsSteps
    {
    private Account _currentAccount;
    private Account _savingAccount;

    [Given(@"my Current account has a balance of (.*)")]
    public void GivenMyCurrentAccountHasABalanceOf(decimal p0)
    {
    _currentAccount = new Account(p0);
    }

    [Given(@"my Savings account has a balance of (.*)")]
    public void GivenMySavingsAccountHasABalanceOf(decimal p0)
    {
    _savingAccount = new Account(p0);
    }

    [When(@"I transfer (.*) from my Current account to my Savings account")]
    public void WhenITransferFromMyCurrentAccountToMySavingsAccount(decimal p0)
    {
    _currentAccount.Withdraw(p0);
    _savingAccount.Deposit(p0);
    }

    [Then(@"I should have (.*) in my Current account")]
    public void ThenIShouldHaveInMyCurrentAccount(decimal p0)
    {
    Assert.AreEqual(_currentAccount.Balance, p0);
    }

    [Then(@"I should have (.*) in my Savings account")]
    public void ThenIShouldHaveInMySavingsAccount(decimal p0)
    {
    Assert.AreEqual(_savingAccount.Balance, p0);
    }
    }
    }

    运行测试

    Passed Test

    编写Low-Level Specification

    如果说此前可执行的Specification还是一个Scenario的简单映射,那么这里的Low-Level Specification则可以理解为TDD里的单元测试了。这一步的工作,就是仁者见仁、智者见智了,需要根据具体的业务规则去逐个编写,并保证足够的覆盖率,以驱动整个功能的逐步实现。

    Low-Level Specification与之前Specification分割得到的Then分句相比,Then里放简单的断言,再用Low-Level Specification更细粒度的单元测试来弥补Then的不足。

    生成Living Documentation

    归档主要还是依赖自动化的工具,比如VS自带的测试报告或者SpecLog之类更专业的工具等等。

  • 相关阅读:
    学习之路
    cordova配置icon和splash
    cardova-android打包
    数组元素最大差值的问题
    病毒攻击
    STL模板中List
    Direct3D API函数
    Direct3D雾化效果浅析
    Direct3D中顶点声明格式
    DirectX9.0 Direct3D Graphics Pipeline 总结
  • 原文地址:https://www.cnblogs.com/Abbey/p/4999634.html
Copyright © 2020-2023  润新知