about 3 years ago

RSpec 是 Rails 的其中一種測試框架,深受國外社群的愛戴,它的撰寫方式簡單易懂,非常好上手;語意化的設計讓測試代碼變得直觀,即便是初次學習的工程師也能夠迅速理解。

然而,台灣關於 RSpec 的文獻實在不多(找過比較完整的介紹是 ihower 的實戰聖經),加上 RSpec 還在發展中,不同派別的語法和 convention 很容易混在一起,要釐清它們並整理出一個最簡單可行的版本實在有些因擾。 但其實都沒想像中的困難,看完下面的敘述,你也能立刻寫出一個可以運行的測試代碼。

設定一個 RSpec 測試環境

由於 RSpec 不是 Rails 預設的 test framework ,在進行測試代碼開發前,我們必需先準備好測試環境。

安裝 rspec-rails 套件

在 Gemfile 裡將 rspec-rails 設定在 development 和 test 的 group 底下,並執行 bundle install 的指令,它會自動安裝好所需的套件。

Gemfile
group :development, :test do
  gem 'rspec-rails', '~> 3.0.0.beta'
end
建立 rspec-rails 基本設定

執行 rails generate rspec:install 的指令,它會自動新增 RSpec 所需的檔案和設定。

Terminal
#=> create  .rspec
#=> create  spec
#=> create  spec/spec_helper.rb
建立一個 test 專用的 database

在 database.yml 中設定 test db 的參數

database.yml
development: &default

  adapter: mysql2

  encoding: utf8

  database: blog_development

  host: localhost

  username: root

  password: ""



test: &TEST

  <<: *default

  database: blog_test

接著執行 rake db:test:prepare ,rake 會根據 schema 新增一個測試用的 database。

學會 RSpec 的基礎語法

RSpec 提供很多 sugar syntax 和 features 讓我們寫出漂亮的測試代碼,這些語法經常會對初學者的腦袋造成混亂。 其實只要幾個基本的語法,就可以寫出簡單的測試。 下面將以 board 為例,說明如何運用它們

board.rb
#  title         :string(255)

#  description   :text

 
class Board < ActiveRecord::Base
end

執行 rails g rspec:model board 指令,它會在 spec 的 model 資料夾底下新增一個 board 的 spec 檔案。

board_spec.rb
require 'spec_helper'

describe Board do
  pending "add some examples to (or delete) #{__FILE__}"
end
context 與 describe

context 和 describe 都是用來宣告 example group 的語法,一般會將 describe 當作測試 feature 的 group。

board_spec.rb
describe "#is_news?"  #=> 井號代表 instance method 的測試

describe ".find_by_title"  #=> 句號代表 class method 的測試

而 context 通常當作 condition 的 group。

context "when title is empty" 
context "when title is News" 
it

每個 it 都代表一個 test example,而測試代碼都必需在 it 的 block 裡宣告才會被執行 ; 在尚未填入 block 之前,it 只會列在 pending 的清單裡。

board_spec.rb
describe Board do
  describe "#is_news?"  do
    it "returns true when eq news"
  end
end

OUTPUT

expect && eq

expect 和 eq 是 test example 裡很常被用到的語法,通常是 expect(預期的對象).to eq(預期的結果)。
由於 blog_test 裡面完全沒有資料,我們必需先產生 Board 的資料再來驗證。

board_spec.rb
it "returns true when eq news" do
  @board = Board.create!(:title => "news")
  expect(@board.is_news?).to eq(true) #=> 在這裡也可以用 be_true 來表示

end

OUTPUT


當 example 測試跑完,RSpec 會顯示 example 的數量和失敗的數量,failures 等於 0 的情況才算測試成功。

學會判斷 RSpec 的測試失敗 message

稍早我們已經知道測試成功的 message,另一方面也必需了解如何從錯誤的訊息中判別,以下圖為例

Red 代表某些 example 失敗了

message 會將失敗的代碼上色並且提供相關的訊息,只要見到紅色的文字出現,就代表有 example 失敗了。

列出失敗的行數與目的

message 會提供失敗的代碼行數和該代碼的測試目的,讓 RD 能夠迅速理解代碼的邏輯。 如圖中的 describe,我們很清楚的知道,當 @board 是 news 的時候 is_news? 應該要 return true。

expect 的 value

message 會印出 expect 的真實 value,例如 @board.is_news? 預期會 return true,但實際上獲得的 value 卻是 false。

← 哪種情況需要寫測試? 如何在 Rails 的 ORM 裡實現 UNION (聯集) →
 
comments powered by Disqus