RSpec學習筆記2:Model測試

RSpec學習筆記2:Model測試

本篇要筆記的是Model的測試。

測試Model就等於測試整個專案的核心,如果這部分有做好的話, 就可以建立高信賴度的測試基礎。

生成撰寫測試內容的檔案

在終端機輸入:

$ bin/rails g rspec:model user

在spec/models下會生成user_spec.rb的檔案。

這個檔案也可以自己手動建立,但用generate的好處就是他會自動生成以下程式碼:

require 'rails_helper'

RSpec.describe User, type: :model do
  pending "add some examples to (or delete) #{__FILE__}"
end

這時在終端機輸入rspec,會顯示:

1 example, 0 failures, 1 pending

接著可以把pending註解或刪除,然後撰寫測試碼。

RSpec.describe User, type: :model do
  <!-- 有姓、名、email、password的話為有效 -->
  it "is valid with a first name, last name, email, and password"
  <!-- 沒有名的話無效 -->
  it "is invalid without a first name"
  it "is invalid without a last name"
  it "is invalid without an email address"
  it "is invalid with a duplicate email address"
  <!-- 以字串形式回傳全名 -->
  it "returns a user's full name as a string"

end

撰寫時,有4個重點:

  • 將預期的結果寫在describe裡

  • 一個example(以it開始的一行程式碼)只預期一個結果

  • 把每個example寫清楚(雖然it之後可以省略,但可能導致程式碼不易讀)

  • 每個example都以動詞開始。不使用should。 (should是以前的用法,可能導致一些技術問題)

以剛剛的程式碼跑測試的話,會顯示:

6 examples, 0 failures, 6 pending

example1

接著來把第一個example寫完:

  <!-- 有姓、名、email、password的話為有效 -->
  it "is valid with a first name, last name, email, and password" do
    user = User.new(
      first_name: "Ruby",
      last_name: "Rails",
      email: "tester@example.com",
      password: "123456",
    )
    expect(user).to be_valid
  end

要注意每一行後面的逗點喔!

這時再跑測試的話,會出現:

6 examples, 0 failures, 5 pending

第一個example已經pass了!

example2

因為篇幅的關係,就只介紹第二個和最後一個example:

  <!-- 沒有名的話無效 -->
  it "is invalid without a first name" do
    user = User.new(first_name: nil)
    user.valid?
    expect(user.errors[:first_name]).to include("can't be blank")
  end

這裡使用的是include這個matcher,用來確認enumerable value中有沒有某個值。

另外,如果想要確認“測試失敗”的情況,有兩種方法:

一種是把to改成to_not,然後跑測試;

另一種是修改原本的程式碼(這裡的話就是指model裡關於first_name的程式碼),再跑測試。

example6

  <!-- 以字串形式回傳全名 -->
  it "returns a user's full name as a string" do
    user = User.new(
      first_name: "John",
      last_name: "Doe",
      email: "johndoe@example.com"
    )
    expect(user.name).to eq "John Doe"
  end

在RSpec要表示等值不是使用==而是使用eq。

測試class method和scope

這個範例使用scope實作了一個可搜尋note的功能,

所以也要針對這部分來進行測試。

在終端機輸入生成測試檔:

$ bin/rails g rspec:model note

在生成的not_spec.rb檔中輸入以下程式碼:

RSpec.describe Note, type: :model do
  <!-- 回傳和搜尋內容相符的notes -->
  it "returns notes that match the search term" do |variable|
    user = User.create(
      first_name: "Joe",
      last_name: "Tester",
      email: "joetester@example.com",
      password: "123456",
    )

    project = user.projects.create(
      name: "Test Project",
    )

    note1 = project.notes.create(
      message: "This is the first note.",
      user: user,
    )

    note2 = project.notes.create(
      message: "This is the second note.",
      user: user,
    )

    note3 = project.notes.create(
      message: "First, preheat the oven.",
      user: user,
    )

    expect(Note.search("first")).to include(note1, note3)
    expect(Note.search("first")).to_not include(note2)

  end
end

如果要測試找不到搜尋標的時,

  it "returns an empty collection when no results are found" do
  
  <!-- 中間的程式碼和上面一樣所以省略 -->

  expect(Note.search("message")).to be_empty
  end

因為試閱的內容就只有到Model測試,

所以筆記就記錄到這邊。

想了解其他Controller、API等測試內容的話,

就請上網購書囉!

“Everyday Rails Testing with RSpec sample application”

Recent post