cucumber 是一款 BDD 的工具,通常用于集成測(cè)試。
如果應(yīng)用是一個(gè)只提供 API 給手機(jī)端調(diào)用的后端程序。本來(lái)并不是很適合使用 cucumber。
不過(guò)隨著開(kāi)發(fā)的深入,我越來(lái)越覺(jué)得單純的 API 測(cè)試(controller 層)無(wú)法表達(dá)用戶的意圖。
而目在開(kāi)發(fā)團(tuán)隊(duì)對(duì)產(chǎn)品的用例也不是非常清楚,沒(méi)有文檔可言的情況下,使用 cucumber 來(lái)編寫用例也是一個(gè)不錯(cuò)的選擇。
使用 cucumber 的好處
在開(kāi)發(fā)應(yīng)用時(shí),我們會(huì)把大的功能點(diǎn)分解成小的功能。但是在理解業(yè)務(wù)邏輯時(shí),我們要從更宏觀的角度看待系統(tǒng)。
Rails 框架的單體風(fēng)格并不足以讓人非常舒服的熟悉一個(gè)系統(tǒng)。因?yàn)?ActiveRecord 的特性,我們只能看到模型之間的關(guān)系,而看不到用戶是是如何和它們交互的。
這就像給你一堆齒輪,轉(zhuǎn)軸和馬達(dá)一樣,你知道如何拼裝它們,但你看不到它們所組成的到底是汽車,飛機(jī)還是輪船。
通過(guò)用戶故事,無(wú)論是開(kāi)發(fā)人員還是業(yè)務(wù)人員都能對(duì)系統(tǒng)有一個(gè)快速直觀的理解。
而 cucumber 就是將用戶故事代碼化的一款工具。
Get Started
如果使用 rails 自帶的 minitest 測(cè)試框架。添加 cucumber 的步驟如下。
-
在 Gemfile 中添加
group :test, :development do gem 'cucumber-rails', :require => false gem 'database_cleaner' end
-
安裝
bundle install rails generate cucumber:install
-
編寫第一個(gè) feature
@require_login Feature: XiaomiSports In order to know about my xiaomi sports As a care user with xiaomi profile binding I want list of my xiaomi sports Scenario: List of the xiaomi sports Given the system knows my xiaomi profile And the system knows about the following sports:: | record_on | step | | 2015-05-25 | 8000 | | 2015-05-26 | 10000 | | 2015-05-27 | 12000 | When the client requests GET "/api/v1/xiaomi_profile/exercise_data?fromDate=2015-05-25&toDate=2015-05-27" Then response should be "200" And the JSON response should be an array with 3 "step" elements
執(zhí)行
bin/rake cucumber
并且實(shí)現(xiàn)相應(yīng)步驟
cucumber 會(huì)自動(dòng)輸出實(shí)現(xiàn)步驟的提示代碼類似于:
You can implement step definitions for undefined steps with these snippets:
Given(/^the system knows about the processions of my corp$/) do
pending # express the regexp above with the code you wish you had
end
只要把上述代碼拷貝到 features/step_definitions/xxxx_steps.rb
中, 然后填寫測(cè)試代碼, 那么執(zhí)行到這段"情節(jié)"時(shí), 代碼塊中的代碼就會(huì)被執(zhí)行.
tips
一些實(shí)用小技巧
使用 tag 來(lái)實(shí)現(xiàn) AOP 的效果
我在上面的代碼中使用了 @require_login 這個(gè) tag, 表示下面的步驟是需要在用戶登錄狀態(tài)下才能完成的.
可以對(duì) tag 添加鉤子函數(shù)來(lái) DRY,features/support/hooks.rb
Before('@require_login') do
# login logic
end
table 的使用
在 cucumber 中使用 table 可以非常直觀的表達(dá)一組數(shù)據(jù)結(jié)構(gòu), 比如上面提到的:
| record_on | step |
| 2015-05-25 | 8000 |
| 2015-05-26 | 10000 |
| 2015-05-27 | 12000 |
在 step 中可以這樣獲取:
Given(/^the system knows about the following sports::$/) do |table|
table.hashes #=> [{"record_on"=>"2015-05-25", "step"=>"8000"}, {"record_on"=>"2015-05-26", "step"=>"10000"}, {"record_on"=>"2015-05-27", "step"=>"12000"}]
end
request header 的設(shè)置方式
直接上代碼, 模擬客戶端的請(qǐng)求
@current_user = FactoryGirl.create(:access_token).user
header 'Accept', 'application/json'
header 'Content-Type', 'application/json'
header 'Token', @current_user.access_tokens.last.token
參考文檔
https://cucumber.io/docs/reference/rails
http://anthonyeden.com/2013/07/10/testing-rest-apis-with-cucumber-and-rack.html
http://www.emilsoman.com/blog/2013/05/18/building-a-tested/