内容简介:根据BDD in action一书的介绍,Behavior-Driven Development (BDD) is a set of software engineering practices
编辑推荐: |
本文来自于csdn,本文主要通过行为驱动开发BDD的例子说明为什么使用行为驱动开发,用什么框架来做行为驱动开发,行为驱动开发的核心原理,希望对您的学习有所帮助。 |
根据BDD in action一书的介绍,
Behavior-Driven Development (BDD) is a set of software engineering practices
designed to help teams build and deliver more valuable, higher quality software faster.
It draws on Agile and lean practices including, in particular, Test-Driven Development
(TDD) and Domain-Driven Design (DDD). But most importantly, BDD provides a common language based on simple, structured sentences expressed in English (or in the native language of the stakeholders) that facilitate communication between project team members and business stakeholders.
翻译成中文的大概意思就是,行为驱动开发是一个软件工程的系列实践,能够帮助团队快速构建和交付更多价值和质量的软件产品。其和敏捷已经精益的开发实践,是一脉相承的,特别是测试驱动开发,已经领域驱动开发。但是最重要的是BDD提供了一种通用的,简单的,结构化的描述语言,这种语言既可以是英语也可以是其他本地的语言,通过他能够很方便让项目成员和业务干系人非常顺畅的沟通需求,及时这些干系人不懂的任何编程语言。下面就是一个例子。
是不是很好读懂,上面其实就叫Feature(特性文件),其遵循的Gherkin标准,其有下面的关键字,很好理解,
1.Feature
2.Background
3.Scenario
4.Given
5.When
6.Then
7.And
8.But
9.*
10.Scenario Outline
11.Examples
这种特性文件,客户,项目经理,BA,QA都能看懂,因为其就是一个故事点或者需求点,而且通过特定的工具,比如cucumber的工具,能够把其自动转换成为代码。开发人员根据自动生成的代码,断言一些预期的行为,并根据这些行为,完成相应的代码实现,在代码实现的基础上,进行重构; 这样就为一个项目中的各个人员了解项目的需求,实现提供了一个很好的交互桥梁。下面是其一个交互的过程。
如果是传统的方式,其交互方式,应该是,
通过对比,大家是不是发现BDD的这种方式,把用户或者客户真正的通过Feature文件联系在一起了,其沟通是顺畅的,QA,BA,开发,测试,客户,用户可以通过这一媒介,进行高效无障碍的沟通,而不是像传统的方式,通过BA进行二次转达,从而丢失了很多重要的需求。
由此可见,其BDD的好处如下:
减少浪费
节省成本
容易并且安全的适应变化
因为少了中间的转达环节,从而能够快速交付产品
下面看一个简单的例子
从上图可以看出,当一个需求过来的时候,先通过项目干系人都能理解的Feature文件,描述项目的User Story, 有的里面还有详细生动的数据范例(example),从而能够让所有的人更加容易理解其需求, 比如
通过上面的数据范例(example)的表格是不是更加容易的理解当前case的意图了。当Feature和Example文件都完成后,借助于第三方的开源框架实现,比如Cucumber,jBehave,SpecFlow等把Feature和Example装换成代码,然后通过第层次的单元测试框架,比如JUnit,NUnit,Spock,RSpec,结合测试驱动开发,从而把业务代码的逻辑实现。真是一举多得。
笔者就以Cucumber和JUnit为例,举一个BDD的例子吧。大家对JUnit比较熟悉,但是对Cucumber可能会相对陌生一点,笔者就花一点笔墨,简单介绍了一下Cucumber。Cucumer是一个实现了BDD的一个框架,其支持下面的语言和框架集成,
是不是感觉很强大啊!!!! 下面进入实战,
1. Maven库的依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>uk.co.claysnow</groupId> <version>1.0</version> <packaging>jar</packaging> <name>Cucumber-JVM Book ATM Example</name> <artifactId>atm-example</artifactId> <properties> <cucumber.version>1.2.0</cucumber.version> <junit.version>4.11</junit.version> <picocontainer.version>2.14.2</picocontainer.version> </properties> <dependencies> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-junit</artifactId> <version>${cucumber.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-picocontainer</artifactId> <version>${cucumber.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.picocontainer</groupId> <artifactId>picocontainer</artifactId> <version>${picocontainer.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12.2</version> <configuration> <argLine>-Duser.language=en</argLine> <argLine>-Xmx1024m</argLine> <argLine>-XX:MaxPermSize=256m</argLine> <argLine>-Dfile.encoding=UTF-8</argLine> <useFile>false</useFile> </configuration> </plugin> </plugins> </build> </project>
2. 安装Cucumber Eclipse插件
为了支持Feature的Gherkin语法,我们需要在Eclipse安装下面的插件:
https://cucumber.io/cucumber-eclipse/update-site
具体安装方法,请到百度或者google搜索。下面看一个具体的例子:
3. Feature文件
Feature: Cash Withdrawal Scenario: Successful withdrawal from an account in credit Given I have deposited $100.00 in my account When I withdraw $20 Then $20 should be dispensed
4. 生成的Java Specification文件
import cucumber.api.java.en.*; import cucumber.api.Transform; import org.junit.*; import support.KnowsTheDomain; import transforms.MoneyConverter; public class AccountSteps { KnowsTheDomain helper; public AccountSteps(KnowsTheDomain helper) { this.helper = helper; } @Given("^I have deposited (\\$\\d+\\.\\d+) in my account$") public void iHaveDeposited$InMyAccount(@Transform(MoneyConverter.class) Money amount) throws Throwable { helper.getMyAccount().deposit(amount); Assert.assertEquals("Incorrect account balance -", amount, helper.getMyAccount().getBalance()); } }
mport cucumber.api.java.en.*; import org.junit.*; import support.KnowsTheDomain; import transforms.MoneyConverter; public class CashSlotSteps { KnowsTheDomain helper; public CashSlotSteps(KnowsTheDomain helper) { this.helper = helper; } @Given("^\\$(\\d+) should be dispensed$") public void $ShouldBeDispensed(int dollars) throws Throwable { Assert.assertEquals("Incorrect amount dispensed -", dollars, helper.getCashSlot().getContents()); } }
import cucumber.api.java.en.*; import support.KnowsTheDomain; public class TellerSteps { KnowsTheDomain helper; public TellerSteps(KnowsTheDomain helper) { this.helper = helper; } @When("^I withdraw \\$(\\d+)$") public void iWithdraw$(int amount) throws Throwable { helper.getTeller().withdrawFrom(helper.getMyAccount(), amount); } }
5. Cucumber 测试的运行入口
import cucumber.api.junit.Cucumber; import cucumber.api.CucumberOptions; import cucumber.api.SnippetType; import org.junit.runner.RunWith; @RunWith(Cucumber.class) @CucumberOptions(plugin="pretty", snippets=SnippetType.CAMELCASE) public class RunCukesTest { }
6. 具体的实现
public class Account { private Money balance = new Money(); public void deposit(Money amount) { balance = balance.add(amount); } public Money getBalance() { return balance; } } public class CashSlot { private int contents; public int getContents() { return contents; } public void dispense(int dollars){ contents = dollars; } } import java.util.regex.Matcher; import java.util.regex.Pattern; public final class Money { private final int dollars; private final int cents; public Money() { this.dollars = 0; this.cents = 0; } public Money(int dollars, int cents) { this.dollars = dollars; this.cents = cents; } public Money(String amount) { Pattern pattern = Pattern.compile("^[^\\d]*([\\d]+)\\.([\\d][\\d])$"); Matcher matcher = pattern.matcher(amount); matcher.find(); this.dollars = Integer.parseInt(matcher.group(1)); this.cents = Integer.parseInt(matcher.group(2)); } public int dollars() { return dollars; } public int cents() { return cents; } public Money add(Money amount){ int newCents = cents + amount.cents(); int newDollars = dollars + amount.dollars(); if (newCents >= 100){ newCents -= 100; newDollars++; } return new Money(newDollars, newCents); } public Money minus(Money amount){ int newCents = cents - amount.cents(); int newDollars = dollars - amount.dollars(); if (newCents < 0){ newCents += 100; newDollars--; } return new Money(newDollars, newCents); } @Override public boolean equals(Object other){ boolean equal = false; if (other instanceof Money){ Money otherMoney = (Money)other; equal = (this.dollars() == otherMoney.dollars() && this.cents() == otherMoney.cents()); } return equal; } @Override public String toString() { return String.format("$%01d.%02d", this.dollars(), this.cents()); } } public class Teller { private CashSlot cashSlot; public Teller(CashSlot cashSlot) { this.cashSlot = cashSlot; } public void withdrawFrom(Account account, int dollars) { cashSlot.dispense(dollars); } }
从上面的例子可以看出,其实现的本质和原理如下:
夜深了,该睡了,行为驱动开发的介绍过一段落,行为驱动开发(BDD)你准备好了吗?
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Nature of Code
Daniel Shiffman / The Nature of Code / 2012-12-13 / GBP 19.95
How can we capture the unpredictable evolutionary and emergent properties of nature in software? How can understanding the mathematical principles behind our physical world help us to create digital w......一起来看看 《The Nature of Code》 这本书的介绍吧!
SHA 加密
SHA 加密工具
XML、JSON 在线转换
在线XML、JSON转换工具