話說昨日,健哥讓我分享下怎么用rspec寫模型的測試,頓時一臉懵逼访锻,因為只會些拳腳貓功夫垢揩,趕緊百度谷歌相關(guān)知識,七湊八湊亏推,湊出來下面這篇總結(jié)学赛,參考過的文檔和博客如下(感興趣的可以去看看):
- rspec入門教程: http://www.reibang.com/p/1db9ee327357
- 1000 個小時學(xué)會 Rails - 003 RSpec 行為驅(qū)動測試簡介: https://ruby-china.org/topics/2848
- RSpec 中 let 和 subject 的區(qū)別:https://ruby-china.org/topics/9271
- Ruby on Rails 自動化測試: https://ihower.tw/rails4/testing.html
- let和before的區(qū)別: http://stackoverflow.com/questions/5974360/rspec-difference-between-let-and-before-block
Step1. 新建一個rails應(yīng)用
話不多說,讓我們創(chuàng)建一個rails 新應(yīng)用吞杭,從頭開始體驗這一奇妙的旅程盏浇;
rails new demo
該應(yīng)用結(jié)構(gòu)如下:
可以看到,在rails中芽狗,默認(rèn)使用的測試工具是Test::Unit
绢掰,而不是Rspec
,怎么替換掉呢?
Step 2: 安裝 Rspec
在Rails的配置文件Gemfile配置文件中,配置下面信息
group :development, :test do
gem 'byebug', platform: :mri
gem 'rspec-rails', '3.5.1'
# gem 'factory_girl_rails', '4.7.0'
# gem 'faker', '1.6.6'
end
我們沒有必要單獨的安裝RSpec
, 因為它是rspec-rails的依賴件會被自動安裝童擎, 執(zhí)行bundle install
或者bundle install --without production
來安裝使用的gem.
執(zhí)行安裝RSpec
的命令:
rails generate rspec:install
該命令執(zhí)行完畢之后,會產(chǎn)生一個文件夾spec,該文件夾下面有spec/spec_helper.rb
這個文件,spec_helper.rb
用來設(shè)置測試的配置信息.
下面是spec的固定的規(guī)范,固定的格式.
describe XXX do
it XXX do ......
end
end
包含了一個 describe 塊以及其中的一個測試用例(sample)滴劲,以 it "..." do 開頭的代碼塊就是一個用例.
可以看到,spec文件夾以及相關(guān)文件創(chuàng)建完成。
Step 3:創(chuàng)建模型和方法
既然我們要介紹模型測試的方法顾复,那么讓我們創(chuàng)建一個模型: Girl(女孩班挖,相信大家都比較喜歡),來做一個簡單的測試演示:
rails generate model Girl
該命令創(chuàng)建的文件如下:
note:在spec/models/ 創(chuàng)建的 girl_spec.rb文件就是我們寫測試用例的地方(一般這種文件的后綴常用_spec)芯砸。
創(chuàng)建模型后, 執(zhí)行遷移命令:
bin/rake db:migrate
下面讓我們開始編寫模型方法:
既然是girl萧芙,大家肯定都關(guān)心其是否單身给梅,是否漂亮。
如果單身的話双揪,就代表自己有機會追到她破喻,如果既單身又漂亮的話,一般就會符合我等屌絲的口味盟榴。
我們定義這兩個屬性曹质,以及對應(yīng)的方法;
app/models/girl.rb 文件內(nèi)容如下:
class Girl < ApplicationRecord
attr_accessor :single, :beautiful
def initialize(params)
self.single = params[:single]
self.beautiful = params[:beautiful]
end
# 是否有機會
def have_chance?
self.single
end
# 是否符合你的口味
def suit_my_taste??
self.single && self.beautiful
end
end
Step 4: 編寫測試用例 并執(zhí)行
針對我們編寫的兩個模型方法擎场,我們開始在girl_spec.rb文件中編寫相應(yīng)的測試:
以 it "..." do 開頭的代碼塊就是一個用例.
首先構(gòu)建一個單身羽德,但不漂亮的女孩,來作為我們的測試數(shù)據(jù)迅办;
expect 語句 可以對返回的結(jié)果進行期望值處理宅静,滿足expect語句,即代表通過此測試用例站欺;
require 'rails_helper'
RSpec.describe Girl, type: :model do
# 測試用例1
# 創(chuàng)建了一個 單身 但不漂亮的 女孩, 來驗證 have_chance? 方法
it "have chance? {single but not beautiful}" do
params = { single: true, beautiful: false }
girl = Girl.new(params)
expect(girl.have_chance?).to eq(true)
end
end
rspec測試命令格式: ruby rspec file_path/file_name
運行如下測試命令:運行g(shù)irl_spec.rb文件中的所有測試用例
rspec spec/models/girl_spec.rb
運行結(jié)果如下圖:
和
Test::Unit
一樣姨夹,用一個極富深意的點,告訴我們測試通過矾策!太棒了磷账!這是我們寫的第一個 RSpec
測試,歡呼贾虽!1 example, 0 failures 代表: 總共1個測試用例逃糟,有0個運行失敗蓬豁;
接下來绰咽,書寫第2個測試用例-(測試該女孩是否符合你的口味)
在
girl_spec.rb
文件中,添加第2個測試用例:
require 'rails_helper'
RSpec.describe Girl, type: :model do
# 測試用例1
# 創(chuàng)建了一個 單身 但不漂亮的 女孩, 來驗證 have_chance? 方法
it "have chance? {single but not beautiful}" do
params = { single: true, beautiful: false }
girl = Girl.new(params)
expect(girl.have_chance?).to eq(true)
end
# 測試用例2
# 創(chuàng)建了一個 單身 但不漂亮的 女孩, 來驗證 suit_my_taste? 方法
it "suit my taste? {single but not beautiful}" do
params = { single: true, beautiful: false }
girl = Girl.new(params)
expect(girl.suit_my_taste?).to eq(true)
end
end
運行如下測試命令:運行g(shù)irl_spec.rb文件中的所有測試用例
rspec spec/models/girl_spec.rb
運行結(jié)果如下圖:
如圖所示:首行返回了
.F
, "."代表第1個測試用例通過地粪,"F"第2個測試用例沒通過(False)在
Failures
(失敗詳情中 )可以看到:expected:true, got:false,(期望值true, 實際獲得false), 所以沒通過取募。
2 examples, 1 failure 代表: 總共2個測試用例,有1個運行失旙〖肌玩敏;
解釋:很顯然,在我們expect語句中付魔,期望值是true聊品,實際上,該女孩單身几苍,但不漂亮;
suit_my_taste?
方法 會返回false; 所以無法通過expect語句陈哑,則該測試用例會返回false妻坝,代表沒通過此測試用例伸眶;
接下來,在第3個測試用例中刽宪,創(chuàng)建一個 既單身又漂亮的女孩 來測試 suit_my_taste?
方法 的返回結(jié)果厘贼;
require 'rails_helper'
RSpec.describe Girl, type: :model do
# 測試用例1
# 創(chuàng)建了一個 單身 但不漂亮的 女孩, 來驗證 have_chance? 方法
it "have chance? {single but not beautiful}" do
params = { single: true, beautiful: false }
girl = Girl.new(params)
expect(girl.have_chance?).to eq(true)
end
# 測試用例2
# 創(chuàng)建了一個 單身 但不漂亮的 女孩, 來驗證 suit_my_taste? 方法
it "suit my taste? {single but not beautiful}" do
params = { single: true, beautiful: false }
girl = Girl.new(params)
expect(girl.suit_my_taste?).to eq(true)
end
# 測試用例3
# 創(chuàng)建了一個 既單身又漂亮的 女孩, 來驗證 suit_my_taste? 方法
it "suit my taste? {single but not beautiful}" do
params = { single: true, beautiful: true }
girl = Girl.new(params)
expect(girl.suit_my_taste?).to eq(true)
end
end
Tips 1:如果只想運行g(shù)irl_spec.rb測試文件中的某一個測試用例,該怎么處理圣拄?
rspec 測試單個用例的命令格式: ruby rspec file_path/file_name:LineNumber
即:加上冒號和it語句塊對應(yīng)的行號嘴秸;
運行如下測試命令:運行g(shù)irl_spec.rb文件中的第3個測試用例:(第3個it ...do 對應(yīng)的行號為23)
rspec spec/models/girl_spec.rb:23
運行結(jié)果如下圖:
解釋:"."代表 該測試用例通過。
Step 5: 優(yōu)化
Tip 2: 為了遵循Ruby
的 DRY原則(Don't repeat yourself), 下面介紹一下before庇谆,subject岳掐,let的用法饭耳;
1. before的用法
before(:each)會在每個測試用例執(zhí)行前, (每段it之前執(zhí)行)
before(:all) 會所有測試用例執(zhí)行前串述,只執(zhí)行一次,(整段describe前只執(zhí)行一次)
假設(shè)要為構(gòu)建出的不同實例對象寞肖,測試它們的每個模型方法纲酗,
在此,我選用before(:all)來優(yōu)化代碼:
require 'rails_helper'
RSpec.describe Girl, type: :model do
before(:all) do
params_1 = { single: true, beautiful: false }
params_2 = { single: true, beautiful: true }
@girl_1 = Girl.new(params_1)
@girl_2 = Girl.new(params_2)
end
########################################################
# 測試用例1-1
# 創(chuàng)建了一個 單身 但不漂亮的 女孩, 來驗證 have_chance? 方法
it "have chance? {single but not beautiful}" do
expect(@girl_1.have_chance?).to eq(true)
end
# 測試用例1-2
# 創(chuàng)建了一個 單身 但不漂亮的 女孩, 來驗證 suit_my_taste? 方法
it "suit my taste? {single but not beautiful}" do
expect(@girl_1.suit_my_taste?).to eq(true)
end
########################################################
# 測試用例2-1
# 創(chuàng)建了一個 單身 但不漂亮的 女孩, 來驗證 have_chance? 方法
it "have chance? {single but not beautiful}" do
expect(@girl_2.have_chance?).to eq(true)
end
# 測試用例2-2
# 創(chuàng)建了一個 既單身又漂亮的 女孩, 來驗證 suit_my_taste? 方法
it "suit my taste? {single but not beautiful}" do
expect(@girl_2.suit_my_taste?).to eq(true)
end
end
運行如下測試命令:運行g(shù)irl_spec.rb文件中的所有測試用例
rspec spec/models/girl_spec.rb
運行結(jié)果如下圖:
解釋:".F.."代表第2個測試用例沒通過,其他測試用例均通過新蟆。
2. subject用法
subject { ... } 定義了一個叫做 subject 的方法, 它返回了代碼塊內(nèi)定義的那個對象.
subject可以用來配合should進行隱式調(diào)用觅赊,何為隱式調(diào)用?(見參考鏈接3琼稻,本文暫不講述)
如果你要使用主動式的 expect茉兰,那么可以給subject起名字(非隱式調(diào)用):
在上述girl_spec.rb
文件中 添加如下代碼 也可行:
# 使用 subject
subject(:girl_1){ @girl_1 }
subject(:girl_2){ @girl_2 }
it "girl_1.have chance?" do
expect(girl_1.have_chance?).to eq(true)
end
it "girl_1.suit my taste?" do
expect(girl_1.suit_my_taste?).to eq(true)
end
it "girl_2.have chance?" do
expect(girl_2.have_chance?).to eq(true)
end
it "girl_2.suit my taste?" do
expect(girl_2.suit_my_taste?).to eq(true)
end
3. let的用法
let和before 有區(qū)別,詳見參考鏈接5
在上述girl_spec.rb 文件中 添加如下代碼 也可行:
# 使用let
let(:girl1){ Girl.new({ single: true, beautiful: false }) }
let(:girl2){ Girl.new({ single: true, beautiful: true }) }
it "girl1.have chance?" do
expect(girl1.have_chance?).to eq(true)
end
it "girl1.suit my taste?" do
expect(girl1.suit_my_taste?).to eq(true)
end
it "girl2.have chance?" do
expect(girl2.have_chance?).to eq(true)
end
it "girl2.suit my taste?" do
expect(girl2.suit_my_taste?).to eq(true)
end
結(jié)語
是不是不過癮欣簇?大家是否也發(fā)現(xiàn)规脸,要對自己的模型方法進行一個完善的測試,需要構(gòu)建合法的數(shù)據(jù)熊咽,手動構(gòu)建數(shù)據(jù)的量太少莫鸭,無法滿足大量測試數(shù)據(jù)的需求,于是乎横殴,工廠女孩(factory_girl
)就要出場了, 另外一個角色就是faker
(這個可不是LOL界的faker大魔王), 它能夠構(gòu)建類似真實的數(shù)據(jù)被因,兩者結(jié)合,威力無窮衫仑,欲知后事如何梨与,且聽下回分解...