Background能夠放置一些共有的描述,重構好幫手。
java
對於公用的Background,不會被多個scenario共享,每一個scenario會獨立運行本身的Background,僅僅起到了代碼複用的做用ios
Cucumber不建議Background涉及太多技術方面的描述,scenario也要簡潔web
能夠這麼定義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 | | | |
解析能夠這麼作api
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是不可變的,app
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)
因此想增刪改只能這麼作dom
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的過濾,因此手動篩選ide
@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