總結起來就是在說用戶寫scenarios ,程序員寫實現java
Refer toios
Extreme Programming Explained: Embrace Change [Bec00]git
Test Driven Development: By Example [Bec02]程序員
http://behaviour-driven.org/ web
建立一個cucumber caseredis
引入相關jarapache
<dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-java8</artifactId> <version>${cucumber.version}</version> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-junit</artifactId> <version>${cucumber.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-core</artifactId> <version>${cucumber.version}</version> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-jvm-deps</artifactId> <version>1.0.5</version> </dependency>
最終引出了完整feature的樣子,Examples的部分很像Spock裏的Data Tablesapi
Feature: Checkout Scenario Outline: Checkout bananas Given the price of a "banana" is 40c When I checkout <count> "banana" Then the total price should be <total>c Examples: | count | total | | 1 | 40 | | 2 | 80 |
feature默認是找同package下的definition去執行框架
關鍵字:
jvm
Feature Background Scenario Given When Then And But * Scenario Outline Examples
如下引入一個例子
Feature: Feedback when entering invalid credit card details In user testing we've seen a lot of people who made mistakes entering their credit card. We need to be as helpful as possible here to avoid losing users at this crucial stage of the transaction. Background: Given I have chosen some items to buy And I am about to enter my credit card details Scenario: Credit card number too short When I enter a card number that's only 15 digits long And all the other details are correct And I submit the form Then the form should be redisplayed And I should see a message advising me of the correct number of digits Scenario: Expiry date must not be in the past When I enter a card expiry date that's in the past And all the other details are correct And I submit the form Then the form should be redisplayed And I should see a message telling
A Template for Describing a Feature [Feature Injection template (from Chris Matts and Liz Keogh)]
In order to <meet some goal> As a <type of stakeholder> I want <a feature>
原則上,scenario之間,必須無依賴
最基礎的樣式
Scenario: Successful withdrawal from an account in credit Given I have $100 in my account # the context When I request $20 # the event(s) Then $20 should be dispensed # the outcome(s)
花樣寫法
Scenario: Attempt withdrawal using stolen card Given I have $100 in my account But my card is invalid When I request $50 Then my card should not be returned And I should be told to contact the bank
or
Scenario: Attempt withdrawal using stolen card Given I have $100 in my account Given my card is invalid When I request $50 Then my card should not be returned Then I should be told to contact the bank
or
Scenario: Attempt withdrawal using stolen card * I have $100 in my account * my card is invalid * I request $50 * my card should not be returned * I should be told to contact the bank
以#開頭的行爲注視
# This feature covers the account transaction and hardware-driver modules Feature: Withdraw Cash In order to buy beer As an account holder I want to withdraw cash from the ATM # Can't figure out how to integrate with magic wand interface Scenario: Withdraw too much from an account in credit Given I have $50 in my account # When I wave my magic wand And I withdraw $100 Then I should receive $100
傳說支持六十多種語言,例如挪威語
# language: no Egenskap: Summering For å unngå at firmaet går konkurs Må regnskapsførerere bruke en regnemaskin for å legge sammen tall Scenario: to tall Gitt at jeg har tastet inn 5 Og at jeg har tastet inn 7 Når jeg summerer Så skal resultatet være 12
ps.一個項目裏支持多個不一樣語言描述的feature,可是由於每個配置對應一個feature,因此在同一個feature裏的scenario都要用同一種語言描述。
若是使用Maven的話,在pom裏添加配置,用來跑test case
<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>
默認這麼跑Test開頭結尾或者TestCase結尾的文件
"**/Test*.java" - includes all of its subdirectories and all java filenames that start with "Test". "**/*Test.java" - includes all of its subdirectories and all java filenames that end with "Test". "**/*TestCase.java" - includes all of its subdirectories and all java filenames that end with "TestCase".
對於Cucumer來講,GIVEN, WHEN, THEN, AND, BUT是同一個東西,都是繼承的@StepDefAnnotation
@StepDefAnnotation
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface StepDefAnnotation { }
@Given
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @StepDefAnnotation @Documented public @interface Given { String value(); long timeout() default 0L; }
@When
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @StepDefAnnotation @Documented public @interface When { String value(); long timeout() default 0L; }
@Then
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @StepDefAnnotation @Documented public @interface Then { String value(); long timeout() default 0L; }
@And
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @StepDefAnnotation @Documented public @interface And { String value(); long timeout() default 0L; }
@But
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @StepDefAnnotation @Documented public @interface But { String value(); long timeout() default 0L; }
看起來新增一門語言的實現很簡單...
強調了使用各類註解的時候要注意語義語境,不要模棱兩可。
最經常使用的一些正則
\d stands for digit, or [0-9]. \w stands for word character, specifically [A-Za-z0-9_]. Notice that underscores and digits are included but not hyphens. \s stands for whitespace character, specifically [ \t\r\n]. That means a space, a tab, or a line break. \b stands for word boundary, which is a lot like \s but actually means the opposite of \w. Anything that is not a word character is a word boundary.
匹配實例
Scenario: Transfer funds from savings into checking account #1 Given I have deposited $10 in my Checking Account #2 And I have deposited $500 in my Savings Account #3 When I transfer $500 from my Savings Account into my Checking Account #4 Then the balance of the Checking Account should be $510 #5 And the balance of the Savings Account should be $0 #6 But I have deposited $ in my Checking Account #7 But I have deposited $100 in my Checking Accounts #8 But I have deposited $100 in your Checking Account #9 But I have deposited $100 in your Checking Account ANCHORS
@Given("I have deposited \\$(\\d+) in my (\\w+) Account") // + = 1 or more public void iHaveDeposited$InMyAccount(int amount, String accountType) { // TODO: code goes here }// #1	
@Given("I have deposited \\$(\\d*) in my (\\w+) Account") // * = 0 , 1 or more public void iHaveDeposited$InMyAccount(int amount, String accountType) { // TODO: code goes here }// #1	
@Given("I have deposited \\$(\\d+) in my (\\w+) Accounts?") //? = 0 or 1 public void iHaveDeposited$InMyAccount(int amount, String accountType) { // TODO: code goes here }// #1	
@Given("^I have deposited \\$(\\d*) in my (\\w+) Account$") //^ ... $ = specific matching public void iHaveDeposited$InMyAccount(int amount, String accountType) { // TODO: code goes here }// #1
@Given("I have deposited \\$(\\d+) in (?:my|your)my (\\w+) Account") // (?: ... | ...) = or public void iHaveDeposited$InMyAccount(int amount, String accountType) { // TODO: code goes here }// #1	
How Cucumber executes a scenario
Scenario的五種狀態
Failed // assert fail or definition error Pending // throw new PendingException() Undefined // cannot match Skipped //the left case after Assert fail or Pending Passed
這段代碼體現了一些人可能忽略的地方: 即便是junit這樣第三方框架的assert,也是隻是拋出了java的AssertionError
import org.junit.*; import static org.junit.Assert.*; public class AssertionExample { public static void main(String[] args) { try { assertTrue(false); } catch (AssertionError e) { System.out.print("Exception was raised was "); System.out.println(e.getClass().getName()); //java.lang.AssertionError } } }
PendingException至關於 TODO
import cucumber.api.java.en.*; import cucumber.api.PendingException; public class Steps { @Given("^I have deposited \\$(\\d+) in my account$") public void iHaveDeposited$InMyAccount(int amount) throws Throwable{ // Write code here that turns the phrase above into concrete actions throw new PendingException(); }
result:
---- T E S T S ------ Running RunCukesTest Feature: Cash Withdrawal Scenario: Successful withdrawal from an account in credit Given I have deposited $100 in my account cucumber.api.PendingException: TODO: implement me at nicebank.Steps.iHaveDeposited$InMyAccount(Steps.java:11) 1 Scenarios (1 undefined) 1 Steps (1 pending)
--strict 用於命令行模式的返回值
兩種狀況會運行失敗
step definition定義有誤
assertion不經過