Rails 使用 RSpec 寫測試:基本說明及安裝篇

Adler @ 2014-07-23


RSpec完整基礎教學(含8部影片)

為什麼網站或軟體開發還要額外寫測試?關於這點,在ihower的投影片裡頭已經講得非常詳細了。簡單來說,網站規模大時,如果每個功能都要在瀏覽器上一個一個測試,只會天荒地老而已;另外,軟體或網站未來在擴充功能時,如果已經有完整的測試碼,可以確保在編修時舊功能不受影響。

比起Rails內建的測試,RSpec的測試寫法較貼近日常生活中的英文語句,閱讀起來較無障礙,這篇文章主要是讓大家了解一下RSpec的基本用法,讓大家有個概念,未來在寫Rails時,可以先使用RSpec撰寫測試,再開始撰寫程式。這種撰寫方式又稱為Test Driven Development或Behavior Driven Development。

在Railscasts裡面,Ryan Bates也講到:『開發Rails時,根本不需要開瀏覽器,等你把後端全部撰寫完成,要動到view或前端功能時,再開瀏覽器吧!』希望我也早日能到這個階段......

Ruby版本:2.1.2
Rails版本:4.1.0
系統:MAC OSX 10.9.4
開啟一個新的Rails application

安裝

首先到Gemfile

group :test, :development do
  gem "rspec"
  gem "rspec-rails"
end

意思是我們只在test和development環境底下安裝即可,等到production階段時,就不需要安裝囉!(到實際production環境時就已經不叫『測試』了)接下來到command line執行bundle,將gem安裝上去,並安裝rspec。

$ rails generate rspec:install

接下來會看到RSpec為你建立了一個spec的資料夾,我們所有的測試都會在裡面進行。這時候可以直接輸入rspec指令,他會自動尋找所有spec資料裡面的測試項目進行測試;由於我們現在什麼都沒有,所以就會看到 0 examples, 0 failures 這個皆大歡喜的結果。到此算是安裝完成。

不過如果你有看到一大串的錯誤訊息,開頭是: warning: loading in progress, circular require considered harmful 。這是rspec跟許多其他gem有不相容的問題,並非嚴重的錯誤,但錯誤訊息實在太龐大,會影響到我們開發的視線,所以我們需要到資料夾最上層的地方找到.rspec這個檔案,把 --warning 這個敘述移除,就可以移除這個錯誤訊息。

--color
--warning
--require spec_helper

RSpec基本結構說明

安裝完成以後,簡單說明一下測試的寫法。首先到spec資料夾底下,手動建立一個 example_spec.rb的檔案,注意:所有測試檔案都需要使用 _spec.rb 當作結尾,RSpec才抓得到。

接下來我們在檔案中加入幾個敘述

require "rails_helper"

describe "The integer i" do
    i = 1

    it "should be 1" do
        i.should == 1
    end 

    it "should larger than 0" do
        i.should > 0
    end

    it "should be 2" do
        i = i + 1
        expect(i).to be 5 
    end

end

首先,第01行的require方法,是要讓我們可以使用Rails特別為RSpec設計的語法,所以每個spec檔案開頭都要加入這個敘述。第03行開始就是測試內容,他的結構最外層是describe...do,意思是我們描述某個事件,而事件當中會包含幾個測試(RSpec中稱為example),每一個example都是用 it...do 的方式進行。

所以在上述範例中,可以看到我們先設定describe是 "The integer 1" 代表我們要對這個東西進行測試,文字敘述寫得越明白越好,最好是簡潔有力又好懂,對自己或別人未來要看的時候比較方便。

接下來是連續三個example,每一個example都包含了should或expect的說法,這兩個東西是RSpec測試的核心,因為我們就是藉由『期望』一些特定條件的達成,讓整個程式可以順利進行。已上面的例子來看,我們先設定好 i = 1 ,所以在第一個敘述當中,我們設定一個條件是 i.should == 1 ,如果i不是1,就會有錯誤產生。

最後要補充的是,should和expect是兩種不同的用法,但有一樣的結果,純粹就是兩種撰寫風格。關於用法的不同,可在說明文件中了解。

基本錯誤與修改

在上述的例子中,我們需要在command line中執行,檢查是否能夠順利通過。有兩種撰寫方法:

$ rspec
$ rspec spec/example_spec.rb

第01行會搜尋整個Rails當中的測試項目進行測試,而第02行只會執行單一項目,要注意指定檔案時必須寫出完整的路徑。

就上述例子來看,執行以後,會發現一個錯誤。

Failures:

  1) The integer i should be 2
     Failure/Error: expect(i).to be 5

       expected # => 5
            got # => 2

代表我們在檔案中撰寫的測試內容有錯,因為 i = i + 1 計算過後是2,而非5,所以就有這樣的錯誤訊息。我們可以回到檔案中進行修改預期的結果,讓他變成 expect(i).to be 2,再執行一次rspec,就會看到所有測試都順利通過了。

到這邊算是了解RSpec如何運作了!但目前為止我們只是自high而已,根本沒有把RSpec放進Rails,也不知道要如何依照測試的項目進行開發。所以下一篇我們就要進行實際的一個BDD (Behavior Driven Development)開發囉!

補充:should用法造成deprecation

Rspec從3.0之後的版本,會在should出現時出現deprecation警告,告訴你這個用法已經過時啦~鼓勵大家使用expect,詳細的更新說明可參考他們在部落格上的文章

若堅持要使用should,又不想看到錯誤訊息,則可到spec/spec_helper.rb裡面修改訊息,先找到以下地方:

RSpec.configure do |config|
  #一堆註解
end

接著增加以下內容:

RSpec.configure do |config|
  config.expect_with :rspec do |c|
    c.syntax = [:should, :expect]
  end
end

這段的意思是,設定在RSpec裡面,should和expect的用法都要能正常使用。接下來在所有測試當中,should就都可以使用也不會有錯誤訊息了。