cucumber java從入門到精通(1)初體驗
cucumber在ruby環境下表現讓人驚嘆,作為BDD框架的先驅,cucumber后來被移植到了多平台,有cucumber-js以及我們今天要介紹的主角cucumber-jvm。
先來看一下cucumber,簡單來說cucumber是一個測試框架,就像是juint或是rspec一樣,不過cucumber遵循的是BDD的原則。
BDD就是行為驅動開發,是一種軟件開發流程或者說是軟件開發實踐,具體學術化的東西這里就不介紹了,歸根到底,cucumber具有讓你用自然語言編寫用例的能力。
使用自然語言編寫用例有很多好處,最直觀的好處就是你的客戶在一定的情況下是能夠看懂你的測試用例的。最為項目的最核心因素,客戶決定了項目該做成什么樣,具有什么功能,不需要實現哪些功能。客戶是需求的源泉,如果我們的測試用例很夠很好的跟需求結合起來,比如說我們用自然語言寫的測試用例如果能讓用戶認同,那么在這種情況下,測試用例基本等同於原始的需求文檔了。需求文檔是開發的憑據,這樣一來根據測試用例來實現具體的需求就一定是客戶所希望完成的需求了,畢竟這些需求是經過用戶首肯的。這樣一來,我們就等同於是讓測試用例驅動了開發,這就是所謂的測試驅動開發的一種不太嚴謹的初體驗了。
cucumber就是這樣一種可以把需求轉換為測試用例,讓測試用例即需求的測試框架。概念東西不必太多先把cucumber java跑起來再說。
萬事開頭難,我們以最不自然的方式開始,先苦后甜。
下載jar包
首先下載cucumber-java的相關jar包,我整理了一下,放到了這里。
創建骨架
在這里要用到命令行,我們以windows平台為例。
# 創建名為cucumber_first的文件夾
mkdir cucumber_first
cd cucumber_first
# 創建jars文件夾,把下載下來的jar包全扔進來
mkdir jars
copy where\is\your\jars\*.jars jars
# 創建features文件夾
mkdir features
# 創建step_definitions文件夾
mkdir step_definitions
# 創建implementation文件夾
mkdir implementation
稍微解釋一下這幾個文件夾的作用
- features:用來存放自然語言的用例文件
- step_definitions:用來存放java代碼實現的測試用例
- jars:cucumber-jvm的相關jar包都放在這里
- implementation:存放被測試的代碼,也就是項目的實現文件
讓項目跑起來
依然在命令行里,敲下面的命令
java -cp "./jars/*" cucumber.api.cli.Main features
你會看到下面的提示
No features found at [features]
0 Scenarios
0 Steps
0m0.000s
這行命令的意思就是運行features文件夾下面所有的自然語言測試用例。顯然,我們沒有任何測試用例,因此cucumber提示我們No features found at [features]。
創建feature文件
繼續在命令行里奮戰,我們創建1個空featrue文件
type nul > type nul > features\todo.feature
上面的命令的作用是在features文件夾下面創建名為todo.feature的文件,如果你使用的是linux系統,相應的命令就是touch features\todo.feature
我們的項目
我們的測試項目是實現1個超級簡單的任務管理工具,簡單來說就是實現1個todo list,我們可以往list里面添加任務,如果任務完成則將其置為已完成,僅此而已,小而丑。
定義第1個feature
簡單來說,feature文件的內容就是我們使用自然語言編寫的測試用例,是我們跟用戶進行交流的文檔。feature文件不是亂寫的,它是有一些套路,是有規范的。簡單來說,一個feature文件必須包含下面的一些內容
- Feature:用來描述我們需要測試的功能
- Scenario: 用來描述測試場景
- Given: 前置條件
- When: 描述測試步驟
- Then: 斷言
下面我們要為我們的任務管理工具寫1個測試用例,具體內容如下
Feature: 任務管理
Scenaro: 測試完成任務
Given: 我有3個任務
Then: 我完成了1個任務
Then: 我們還剩2個任務
中英結合,是不是看起來有點怪怪的?確實如此!
重構feature文件
cucumber支持使用40多種語言來描述feature文件,這就意味着我們可以使用中文來寫feature。
下面我們用中文來重構一下
#language: zh-CN
功能:任務管理
場景: 完成1件任務
假設 我的任務清單里有3個任務
當 我完成1件任務之后
那么 我還剩下2件未完成的任務
可以看到Feature關鍵字在中文里可以用場景來替代,這樣看起來就舒服多了。不過注意一下,上面的:
是英文的冒號,最好不要寫成中文的冒號。
feature文件中英文關鍵字對照表
試着在命令行中使用下面的命令:
java -cp "./jars/*" cucumber.api.cli.Main --i18n zh-CN
該命令的輸出結果就是feature文件中英文關鍵字的對照表。
| feature | "功能" |
| background | "背景" |
| scenario | "場景", "劇本" |
| scenario_outline | "場景大綱", "劇本大綱" |
| examples | "例子" |
| given | "* ", "假如", "假設", "假定" |
| when | "* ", "當" |
| then | "* ", "那么" |
| and | "* ", "而且", "並且", "同時" |
| but | "* ", "但是" |
| given (code) | "假如", "假設", "假定" |
| when (code) | "當" |
| then (code) | "那么" |
| and (code) | "而且", "並且", "同時" |
| but (code) | "但是" |
可以看到有些關鍵字對應了多種中文表達,不用困惑,這沒關系,哪種表達方式用起來自然就用哪種。
運行feature
是時候運行一下我們剛寫的feature了。
命令行里運行
java -cp "./jars/*" cucumber.api.cli.Main features
這個命令告訴cucumber,運行所有在features文件夾下的feature文件。
該命令會輸出下面的結果
1 Scenarios (1 undefined)
3 Steps (3 undefined)
0m0.000s
You can implement missing steps with the snippets below:
@假設("^我的任務清單里有(\\d+)個任務$")
public void 我的任務清單里有_個任務(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
@當("^我完成(\\d+)件任務之后$")
public void 我完成_件任務之后(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
@那么("^我還剩下(\\d+)件未完成的任務$")
public void 我還剩下_件未完成的任務(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
逐行解釋一下:
- 1 Scenarios (1 undefined): 我們在feature文件中描述了1個Scenario,但是我們只是描述,沒有實現,這就是所謂的光說不練;
- 3 Steps (3 undefined): 我們描述了3個測試步驟,但我們僅僅是描述而已,沒有實現這些步驟;
- 剩下的代碼片段:告訴我們不要光說不練,要用下面的這些代碼去實現這些場景和步驟;
如果運行時出現亂碼,也就是說cucumber無法解析feature文件的話,記得將feature文件的編碼改為utf8無bom
總結
可以看出,feature文件其實即使測試用例又是需求文檔,當然了一個系統光有描述性質的測試用例和需求文檔是遠遠不夠的,下一節我們將會看到cucumber是怎樣把單元測試用例和自然語言用例無縫關聯的。