BDD
- Given - When - Then
- Given 初始化描述 and 另一个初始化描述
- When 某个行为 and 另一个行为
- Then 获得的结果 and 另外一个结果
代码语言:javascript
复制
test.feature Scenario: As an account owner Given I have no account When I open a new account Then the account balance is 0.00
英文关键词(Keyword) |
对应中文关键词(Equivalemt) |
feature |
功能 |
background |
背景 |
scenarioOutline |
场景大纲、剧本大纲 |
scenano |
场景、剧本 |
examples |
例子 |
given |
假如、假设、假定 |
when |
当 |
then |
那么 |
and |
而且、并且、同时 |
but |
但是 |
1. 修改%MVN_HOME%\conf\settings.xml
找到<mirror>处,加入:
代码语言:javascript
复制
<mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>
2 在工作目录运行
代码语言:javascript
复制
>mvn archetype:generate "-DarchetypeGroupId=io.cucumber" "-DarchetypeArtifactId=cucumber-archetype" "-DarchetypeVersion=4.2.6" "-DgroupId=hellocucumber" "-DartifactId=hellocucumber" "-Dpackage=hellocucumber" "-Dversion=1.0.0-SNAPSHOT" "-DinteractiveMode=false" "-DarchetypeCatalog=local"
形成hellocucumber项目。
3 打开Eclipse,“帮助-eclipse市场”,安装cucumber
4 修改pom.xml
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>hellocucumber</groupId> <artifactId>hellocucumber</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <cucumber.version>4.2.6</cucumber.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>5 <dependencies> <dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-java</artifactId> <version>${cucumber.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-junit</artifactId> <version>${cucumber.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <encoding>UTF-8</encoding> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
5 书写feature文件。test.feature
代码语言:javascript
复制
#language:zh-CN 功能: 作为一名银行客户 我想要拥有一个账户 以便我可以存钱、取钱,并且显示当前余额 场景:我没有账户 假设我没有账户 当我新建账户的时候 那么我的账户余额为0.00元 场景:我已经有了账户 假设我的账户初始余额为0.00元 当我存入100.00元后 那么我的账户余额为100.00元 假设我的账户初始余额为100.00元 当我存入200.00元后 那么我的账户余额为300.00元 假设我的账户初始余额为400.00元 当我取出300.00元后 那么我的账户余额为100.00元
#language:zh-CN 表示用中文写
6 根据test.feature写步骤文件Stepdefs.java
代码语言:javascript
复制
package hellocucumber; import cucumber.api.java.zh_cn.*; import static org.junit.Assert.*; public class Stepdefs { private Account account; @假如("我没有账户") public void 我没有账户() { this.account = null; } @当("我新建账户的时候") public void 我新建账户的时候() { this.account = new Account(); } @那么("我的账户余额为{double}元") public void 我的账户余额为(Double value) { assertEquals(value, this.account.getBalance()); } @假设("我的账户初始余额为{double}元") public void 我的账户初始余额为_元(Double value) { this.account = new Account(); this.account.deposit(value); } @当("我存入{double}元后") public void 我存入_元后(Double value) { this.account.deposit(value); } @当("我取出{double}元后") public void 我取出_元后(Double value) { this.account.withdraw(value); } }
注意,空格都必须一致
7 修改RunCucumberTest.java文件
代码语言:javascript
复制
package hellocucumber; import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucumber; import org.junit.runner.RunWith; @RunWith(Cucumber.class) @CucumberOptions(features = "src/test/java/hellocucumber/test.feature",plugin = {"pretty"}) public class RunCucumberTest { }
features = "src/test/java/hellocucumber/test.feature"指明feature文件位置
8 修改产品代码
代码语言:javascript
复制
package hellocucumber; public class Account { private Double balance = 0.0; public Double getBalance(){ return this.balance; } public Double deposit(Double value) { return this.balance+=value; } public Double withdraw(Double value) { return this.balance-=value; } }
9 运行
代码语言:javascript
复制
[INFO] Scanning for projects... [INFO] [INFO] --------------------< hellocucumber:hellocucumber >--------------------- [INFO] Building hellocucumber 1.0.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hellocucumber --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] [INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ hellocucumber --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hellocucumber --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] [INFO] --- maven-compiler-plugin:3.7.0:testCompile (default-testCompile) @ hellocucumber --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hellocucumber --- [INFO] Surefire report directory: C:\Code\MyJava\JUnit\hellocucumber\target\surefire-reports ------------------------------------------------------- T E S T S ------------------------------------------------------- Running hellocucumber.RunCucumberTest 功能: 作为一名银行客户 我想要拥有一个账户 以便我可以存钱、取钱,并且显示当前余额 场景: 我没有账户 # src/test/java/hellocucumber/test.feature:7 假设我没有账户 # Stepdefs.我没有账户() 当我新建账户的时候 # Stepdefs.我新建账户的时候() 那么我的账户余额为0.00元 # Stepdefs.我的账户余额为(Double) 场景: 我已经有了账户 # src/test/java/hellocucumber/test.feature:12 假设我的账户初始余额为0.00元 # Stepdefs.我的账户初始余额为_元(Double) 当我存入100.00元后 # Stepdefs.我存入_元后(Double) 那么我的账户余额为100.00元 # Stepdefs.我的账户余额为(Double) 假设我的账户初始余额为100.00元 # Stepdefs.我的账户初始余额为_元(Double) 当我存入200.00元后 # Stepdefs.我存入_元后(Double) 那么我的账户余额为300.00元 # Stepdefs.我的账户余额为(Double) 假设我的账户初始余额为400.00元 # Stepdefs.我的账户初始余额为_元(Double) 当我取出300.00元后 # Stepdefs.我取出_元后(Double) 那么我的账户余额为100.00元 # Stepdefs.我的账户余额为(Double) 2 Scenarios (2 passed) 12 Steps (12 passed) 0m0.100s Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.237 sec Results : Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.700 s [INFO] Finished at: 2024-02-01T17:13:15+08:00 [INFO] ------------------------------------------------------------------------ 场景:余额不足 假设我的账户初始余额为600.00元 当我取出300.00元后 那么我的账户余额为300.00元 当我取出300.00元后 那么我的账户显示余额不足 @那么("我的账户显示余额不足") public void 我的账户显示余额不足() { // Write code here that turns the phrase above into concrete actions throw new cucumber.api.PendingException(); } Tests run: 3, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 0.259 sec
代码语言:javascript
复制
@当("我取出{double}元后") public void 我取出_元后(Double value) throws Throwable { this.account.withdraw(value); } @当("我取出{double}元后,显示余额不足") public void 我取出_元后_显示余额不足(Double value) { assertThrows(Throwable.class,()->this.account.withdraw(value)); } public Double withdraw(Double value) throws Throwable { if (value>this.balance) throw new Throwable("余额不足"); else return this.balance-=value; }
代码语言:javascript
复制
#language:zh-CN 功能: 作为一名银行客户 我想要拥有一个账户 以便我可以存钱、取钱,并且显示当前余额 场景大纲:我已经有了账户-表格 假设我的账户初始余额为<初始余额>元 当我存入<存入额>元后 那么我的账户余额为<账户余额>元 例子: | 初始余额| 存入额| 账户余额| | 0.00 |5.0|5.0| | 20.00|2.2|22.2|
在pom.xml加入:
代码语言:javascript
复制
<plugin> <groupId>com.trivago.rta</groupId> <artifactId>cluecumber-report-plugin</artifactId> <version>2.5.0</version> <executions> <execution> <id>report</id> <phase>post-integration-test</phase> <goals> <goal>reporting</goal> </goals> </execution> </executions> <configuration> <sourceJsonReportDirectory> ${project.build.directory}/cucumber-report </sourceJsonReportDirectory> <generatedHtmlReportDirectory> ${project.build.directory}/generated-report </generatedHtmlReportDirectory> </configuration> </plugin>
运行 mvn verify
使用 Cucumber 和 Selenium 对 Web 页面的行为进行测试
代码语言:javascript
复制
# language: zh-CN 功能: 作为一名天猫网的 Web 端用户 我想要搜索到世界上最贵的东西 以便我可以购买世界上最贵的东西
代码语言:javascript
复制
mvn archetype:generate "-DarchetypeGroupId=io.cucumber" "-DarchetypeArtifactId=cucumber-archetype" "-DarchetypeVersion=4.2.6" "-DgroupId=tmall.bdd" "-DartifactId=selenium-bdd" "-Dpackage=selenium.bdd" "-Dversion=1.0.0-SNAPSHOT" "-DinteractiveMode=false" "-DarchetypeCatalog=local"
代码语言:javascript
复制
# language: zh-CN 功能: 作为一名天猫网的 Web 端用户 我想要搜索到世界上最贵的东西 以便我可以购买世界上最贵的东西 场景:打开浏览器,进入天猫网首页假设我没有打开浏览器当打开浏览器并输入“https://www.tmall.com/”的时候那么我可以进入天猫网首页
代码语言:javascript
复制
package tmall.bdd; import io.cucumber.java.zh cn.*; public class StepDefnitions { @假设("我没有打开浏览器") public void 我没有打开浏览器(){ // Write code here that turns the phrase above into concrete actions throw new io.cucumber.java.PendingException(); @当("打开浏览器并输入 http:\\/\\www.tmall.com的时候") public void 打开浏览器并输入天猫网首页的时候(){ // Write code here that turns the phrase above into concrete actions throw new io.cucumber.java.PendingException(); @那么("我可以进入天猫网首页") public void 我可以进入天猫网首页(){ // Write code here that turns the phrase above into concrete actions throw new io.cucumber.java.PendingException(); } }
BDD落地
1与团队确定BDD模式
方案1
产品负责人/业务分析师与客户讨论需求,确认用户故事。
产品负责人/业务分析师在迭代计划会上解释用户故事和验收标准。
在迭代计划会上,敏捷软件开发团队根据验收标准承诺交付。
产品负责人/业务分析师与客户进一步沟通交流,确认敏捷软件开发团队提问题,达成验收标准,或展示设计方案以获取进一步反馈。
重复第2 3 4步,直至敏捷软件开发团队能够承诺交付,在这一过程中可分出多个用户故事。
方案2
产品负责人/业务分析师与客户讨论需求,确认用户故事、验收场景和验收标准。
测试人员与产品负责人/业务分析师和敏捷软件开发团队确认验收标准。
测试团队以 Given-When-Then 的方式编写自动化的测试用例。
产品负责人/业务分析师与客户确认以 Given-When-Then 方式编写的验收标准。
确认完毕后,在迭代计划会上,敏捷软件开发团队根据验收标准承诺交付。
重复第2、 3 、4步,直至敏捷软件开发团队能够承诺交付,在这一过程中可能会拆分出多个用户故事。
敏捷软件开发团队根据客户最终确认的 Given-When-Then 测试用例编写自动化验收测试,并完成敏捷软件开发。
方案3
产品负责人/业务分析师和客户讨论需求,确认用户故事、验收场景和验收标准
测试团队以 Given-When-Then 的方式编写自动化的测试用例。
测试团队与产品负责人/业务分析师和敏捷软件开发团队确认验收标准。
产品负责人/业务分析师与客户进一步沟通交流,确认以 Given-When-Then方:号的验收标准。
确认完毕后,在迭代计划会上,开发团队根据验收标准承诺交付。
重复第2、 3、4步,直至敏捷软件开发团队能够承诺交付,在这一进程中可能会拆分出多个用户故事。
敏捷软件开发团队以通过测试人员编写的自动化测试为完成条件,完成敏捷软开发。
2.选择一个适合当前技术栈的 BDD 自动化框架
3.建立基础的.feature文件
(1)使用通用语言(Ubiquitous Language)编写用户故事和验收测试。
(2)一个没有统一领域语言导致年收入减少 10%的 Bug。
4.在持续集成的任务中运行 BDD 的自动化测试
5.重构 BDD 测试,优化自动化测试的分层结构