Rails 使用 RSpec 寫測試:入門操作篇
RSpec完整基礎教學(含8部影片)
前一篇提到RSpec在Rails當中的安裝,現在要實際執行一次BDD開發,讓大家了解實際流程為何。開發環境與前一篇相同,因此便不再贅述。
開發規格
每一次的網站開發都需要規劃出規格表,不管是為客戶規劃網站、或是新產品開發,都需要有詳細的規格,整個團隊才能目標相同。以下是這篇文章會完成的一個網站。
使用者能夠在網站上產生文章,文章會包含標題、內容欄位
使用者能夠產生評論,藉以回應文章,評論包含內容欄位
每個文章都會有多個回應
文章底下可以看到該篇文章所有回應
文章的標題、內容不能為空白
回應的內容不可為空白
網站首頁是所有文章列表
好了,我們開出了一個簡單的網站規格,我們來把這個東西寫成RSpec的測試,再根據這些測試的內容來撰寫網站程式碼。
首先,進行以下操作,將rails的應用程式建立起來,以及安裝RSpec。
$ rails new rspec_test
修改Gemfile安裝RSpec
$ rails generate rspec:install
修改.rspec檔案解除warning
RSpec測試撰寫
接下來進入正文,根據以上開出來的規格,我們需要建立post和comment的model,讓兩者有從屬關係,以及建立相對應的controller和view。
我們在spec目錄底下,建立一個 integration_spec.rb 檔案,將所有測試寫在裡面,因為稍後我們使用scaffold建立起來資料以後,會有非常多不必要的測試項目,那些部分我們就都跳過。以下是測試內容:
require 'rails_helper'
#這裡進行Post的model測試
RSpec.describe Post, :type => :model do
#在每一個it的測試項目之前,都先建立一個post資料
before(:each) do
@post = Post.new
end
#測試post是否包含標題和內容
it "should contain :title & :content" do
@post.title
@post.content
end
#測試post如果標題空白,就不能儲存
it ":title should not be blank" do
@post.title = nil
@post.save.should == false
end
#測試post如果內容空白,就不能儲存
it ":content should not be blank" do
@post.content = nil
@post.save.should == false
end
#測試post要和comment建立has_many的關係
it "has many comments" do
$post = Post.reflect_on_association(:comments)
$post.macro.should == :has_many
end
end
#這裡進行Comment的model測試
RSpec.describe Comment, :type => :model do
before(:each) do
@comment = Comment.new
end
#測試comment是否包含內容
it "should contain :content" do
@comment.content
end
#測試comment如果內容空白,就不能儲存
it ":content should not be blank" do
@comment.content = nil
@comment.save.should == false
end
#測試comment要和post建立belongs_to的關係
it "belongs to post" do
$comment = Comment.reflect_on_association(:post)
$comment.macro.should == :belongs_to
end
end
由於目前我們什麼資料都還沒有,所以測試都不會通過。為了解決測試項目,我們現在就來實際操作,架構網站。
$ rails generate scaffold post title content
$ rails generate scaffold comment post_id:integer content
這兩個指令會產生許多資料,但我們實際會用到的其實沒那麼多。接下來我們直接來解決測試的問題。
post.rb
class Post < ActiveRecord::Base
validates :title, :content, presence: true
has_many :comments
end
comment.rb
class Comment < ActiveRecord::Base
validates :content, presence: true
belongs_to :post
end
以上兩個檔案的修改,就足以通過所有測試。這時候我們到Command Line執行 $rspec spec/integration_spec.rb 就會看到八項測試全部通過啦!
你可能會覺得,為什麼這麼簡單的東西,測試要寫得這麼複雜?因為目前我們的網站架構還非常簡單,測試內容相對看起來很多,但等到網站規模超大的時候,相對之下測試檔案的內容會是非常少的!
測試route和view:
不過在規格表上還有幾個東西需要解決的:
文章底下可以看到該篇文章所有回應
網站首頁是所有文章列表
如果要在文章底下看到所有回應,代表我們要在view裡面可以檢查有comment的出現,而首頁的設定也需要在route上進行撰寫。以下是我們繼續在integration_spec.rb檔案當中增加的項目:
#這裡進行Post的view測試
RSpec.describe "posts/show", :type => :view do
#建立post和comment的資料,讓同一筆post裡頭含有多筆comment
before(:each) do
@post = assign(:post, Post.create(:title => "Title", :content => "Content"))
@comment_1 = @post.comments.create(:content => "display_comment_1")
@comment_2 = @post.comments.create(:content => "display_comment_2")
end
#測試view裡面,post的顯示頁面要同時顯示他所有的comment
it "renders comments by post" do
render
rendered.should include("display_comment_1")
rendered.should include("display_comment_2")
end
end
#這裡進行route測試
RSpec.describe "Routing root", :type => :routing do
#測試網站首頁是包含所有文章的post index頁面
it "to posts index" do
expect(:get => "/").to route_to("posts#index")
end
為了通過以上測試,首先先找到config/routes.rb
檔案,增加以下幾行:
resources :posts do
resources :comments
end
root to: "posts#index"
上面檔案第04行的部份,就等於把首頁設定到文章列表,已滿足RSpec的測試,所以最後我們就是要確保在post的show.html.erb當中可以看到所有的comments。我們在以下頁面增加幾行程式碼:
def show
@comments = @post.comments.all
end
app/views/posts/show.html.erb
<% @post.comments.each do |c| %>
<%= c.content %>
<% end %>
<%= link_to "New Comment", new_post_comment_path(@post) %>
這樣子在post的show.html.erb當中,就可以看到該篇post的所有comment,不過因為我們是使用scaffold的方法創造兩個model,所以在路徑上還有許多預設路徑需要修改,整個網站才能正常運作,以下是需要修改的地方:
修改第01行
app/views/comments/_form.html.erb
<%= form_for [@post, @comment] do |f| %>
修改第05行
app/views/posts/new.html.erb
<%= link_to 'Back', post_path(@post) %>
修改new的action,約莫第16行
posts_controller.rb
def new
@post = Post.find(params[:post_id])
@comment = @post.comments.build
end
修改完成以後,再執行一次測試,9個測試都順利通過!我們順利的用RSpec建立一個Rails網站囉!