内容简介:根据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)你准备好了吗?
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。