Background可以放置一些共有的描述,重构好帮手。
对于公用的Background,不会被多个scenario共享,每个scenario会独立运行自己的Background,仅仅起到了代码复用的作用
Cucumber不建议Background涉及太多技术方面的描述,scenario也要简洁
可以这么定义Data Tables
Feature: Scenario: Given a board like this: | | 1 | 2 | 3 | | 1 | | | | | 2 | | | | | 3 | | | | When player x plays in row 2, column 1 Then the board should look like this: | | 1 | 2 | 3 | | 1 | | | | | 2 | x | | | | 3 | | | |
解析可以这么做
import cucumber.api.java.en.*; import cucumber.api.PendingException; import cucumber.api.DataTable; import java.util.List; public class BoardSteps { private List<List<String>> board; @Given("^a board like this:$") public void aBoardLikeThis(DataTable table) throws Throwable { this.board = table.raw(); } @When("^player x plays in row (\\d+), column (\\d+)$") public void playerXPlaysInRowColumn(int arg1, int arg2) throws Throwable { System.out.println(board.toString()); throw new PendingException(); } @Then("^the board should look like this:$") public void theBoardShouldLookLikeThis(DataTable arg1) throws Throwable { // Write code here that turns the phrase above into concrete actions // For automatic transformation, change DataTable to one of // List<YourType>, List<List<E>>, List<Map<K,V>> or Map<K,V>. // E,K,V must be a scalar (String, Integer, Date, enum etc) throw new PendingException(); } }
注意,传入的DataTable是不可变的,
java.lang.UnsupportedOperationException at java.util.Collections$UnmodifiableList.set(Collections.java:1311) at tic_tac_toe.BoardSteps.playerXPlaysInRowColumn(BoardSteps.java:20) at *.When player x plays in row 2, column 1(tic_tac_toe.feature:8)
所以想增删改只能这么做
import cucumber.api.java.en.*; import cucumber.api.PendingException; import cucumber.api.DataTable; import java.util.ArrayList; import java.util.List; public class BoardSteps { private List<List<String>> board; @Given("^a board like this:$") public void aBoardLikeThis(DataTable table) throws Throwable { this.board = new ArrayList<List<String>>(); for (List<String> row : table.raw()) { this.board.add(new ArrayList<String>(row)); } } @When("^player x plays in row (\\d+), column (\\d+)$") public void playerXPlaysInRowColumn(int row, int col) throws Throwable { board.get(row).set(col, "x"); } @Then("^the board should look like this:$") public void theBoardShouldLookLikeThis(DataTable expectedTable) throws Throwable { expectedTable.diff(board); } }
Scenario Outline: Withdraw fixed amount Given I have <Balance> in my account When I choose to withdraw the fixed amount of <Withdrawal> Then I should <Outcome> And the balance of my account should be <Remaining> Examples: Successful withdrawal | Balance | Withdrawal | Outcome | Remaining | | $500 | $50 | receive $50 cash | $450 | | $500 | $100 | receive $100 cash | $400 | Examples: Attempt to withdraw too much | Balance | Withdrawal | Outcome | Remaining | | $100 | $200 | see an error message | $100 | | $0 | $50 | see an error message | $0 |
可惜cucumber貌似不支持header和bottom的过滤,所以手动筛选
@When("^I need a table$") public void doSomething(DataTable dataTable) throws Throwable { List<List<String>> rows = dataTable.asLists(String.class); // Either quit having a header in your datatable or remove the first row rows.remove(0); for (List<String> row : rows) { ... } }
Scenario: Ban Unscrupulous Users When I behave unscrupulously Then I should receive an email containing: """ Dear Sir, Your account privileges have been revoked due to your unscrupulous behavior. Sincerely, T he Management """ And my account should be locked
顾名思义,使用Tags和子文件夹维护项目结构
作者说,想当年Cucumber还是个叫RSpec Story Runner的工具,使用.story的后缀名,是不是很像Agile里的user story?作者说后来认为user story脱离于代码,且伴随着user story的变化,理应不影响cucumber中现有的feature,所以推荐不要混淆,即使要引入story的思维,也应该用tag
The features should describe how the system behaves today, but they don’t need to document the history of how it was built; that’s what a version control system is for!
将@keyword置于Feature或者Scenario之前,便是Tag
@nightly @slow Feature: Nightly Reports @widgets Scenario: Generate overnight widgets report ... @doofers Scenario: Generate overnight doofers report
三个用处:
Documentation:标记标识
Filtering:运行或生成报表时的筛选
Hooks:部分运行
Symptom | Problem |
Some of our tests fail randomly. | Flickering scenarios |
We keep breaking tests unintentionally. | Brittle features |
Our features take too long to run. | Slow features |
Our stakeholders don’t read our features. | Bored stakeholders |
Flickering scenarios就是莫名其妙地时好时坏的test case,最常见的有三种:
Shared Environments
Leaky Scenarios
Race Conditions and Sleepy Steps
当然,作者也说,要是真轮到你改bug,实在是找不出方法了,那就把这个test case删掉...
Brittle features就是那些不得不做的却不相干的事
通常有这些可能:
Fixture Data
Duplication
Leaky Scenarios
Tester Apartheid
SLOW FEATURES
这个没啥好说的,慢呗,作者建议真遇到了,可以试试tag+并行
Race Conditions and Sleepy Steps
Lots of Scenarios
Big Ball of Mud
BORED STAKEHOLDERS
貌似就是在说产品经理和开发测试之间的隔膜...
常见的来源如下:
Incidental Details
Imperative Steps
Duplication
Ubiquitous What?
Siloed Features
作者强调Cucumber features就是living documentation
Living: It tests the system automatically so you can work on it safely.
Documentation: It facilitates good communication about the current or planned behavior of the system.
Scenario要写的直观相关简洁
Bad:
Scenario: Check inbox Given a User "Dave" with password "password" And a User "Sue" with password "secret" And an email to "Dave" from "Sue" When I sign in as "Dave" with password "password" Then I should see 1 email from "Sue" in my inbox
Well:
Scenario: Check inbox Given I have received an email from "Sue" When I sign in Then I should see 1 email from "Sue" in my inbox
作者说了命令式编程(Imperative Programming) 和 声明式编程(Declarative Programming)。
Gherkin是命令式的,但是推荐采用声明式的方式去写
作者说 ”想当年我跟Martin Fowler结对编程的时候,受益匪浅!“, 强调DAMP principle: Descriptive and Meaningful Phrases和DRY principle (Don’t Repeat Yourself)
Three Amigos
Three Amigos
The best Gherkin scenarios are created when the three amigos come together, bringing three very different perspectives:
The first amigo is a tester, who thinks about how to break things. The tester will typically come up with lots of scenarios, sometimes covering obscure edge cases and sometimes covering very important ones that no one else had thought of.
The second amigo is a programmer, who thinks about how to make things. The programmer will typically add steps to scenarios, as he asks clarifying questions about what exactly should happen. The third amigo is the product owner, who cares about scope. When the tester thinks of scenarios that hit edge cases the product owner doesn’t care about, she can tell the team to drop that scenario out of scope altogether, or the group can decide to test it with unit tests only. When the programmer explains that implementing a particular scenario will be complicated, the product owner has the authority to help decide on alternatives or to drop it altogether.
Many teams practicing BDD have found the three amigos make a great partnership for thrashing out Gherkin scenarios that the whole team believes in. You don’t have to stop at three amigos, though: invite your team’s user experience specialists or operations staff, for example, if the feature being discussed will affect them.
同上一节,讲了一些问题和解决办法
LEAKY SCENARIOS --〉Test Data Builders
RACE CONDITIONS AND SLEEPY STEPS --〉introduce a fixed-length pause, or sleep
SHARED ENVIRONMENTS --〉 One-Click System Setup
Tester Apartheid --〉 delegate the work of running basic checks to Cucumber
FIXTURE DATA --〉 Nightly Build
LOTS OF SCENARIOS --〉subfolders + tags
BIG BALL OF MUD --〉包含上述多种问题,要确保可测
扯了些管理学的故事和理念
Stop the Line
大野耐一(Taiichi Ohno 1912-1990) Stop the Line at Toyota
DEFECT PREVENTION 四要素
Detect the abnormality.
Stop what you’re doing.
Fix or correct the immediate problem.
Investigate the root cause and install a countermeasure.
第一部分Cucumber fundamentals 就结束了。
作者反复强调 Scenario要写出declarative style