RSpec - 測試替身



本章我們將討論 RSpec Doubles,也稱為 RSpec 模擬物件。Double 是一個可以“代替”另一個物件的 object。您可能想知道這究竟意味著什麼以及為什麼需要它。

假設您正在為學校構建一個應用程式,並且您有一個表示學生教室的類和另一個表示學生的類,也就是說,您有一個 Classroom 類和一個 Student 類。您需要先編寫其中一個類的程式碼,所以假設從 Classroom 類開始:

class ClassRoom 
   def initialize(students) 
      @students = students 
   end 
   
   def list_student_names 
      @students.map(&:name).join(',') 
   end 
end

這是一個簡單的類,它有一個方法 list_student_names,該方法返回一個用逗號分隔的學生姓名字串。現在,我們想要為這個類建立測試,但是如果我們還沒有建立 Student 類,我們該怎麼做呢?我們需要一個測試替身。

此外,如果我們有一個像 Student 物件一樣工作的“虛擬”類,那麼我們的 ClassRoom 測試將不會依賴於 Student 類。我們稱之為測試隔離。

如果我們的 ClassRoom 測試不依賴於任何其他類,那麼當測試失敗時,我們可以立即知道我們的 ClassRoom 類中存在錯誤,而不是其他某個類中存在錯誤。請記住,在現實世界中,您可能正在構建一個需要與其他人編寫的另一個類互動的類。

這就是 RSpec Doubles(模擬物件)變得有用的地方。我們的 list_student_names 方法在其 @students 成員變數中的每個 Student 物件上呼叫 name 方法。因此,我們需要一個實現了 name 方法的 Double。

以下是 ClassRoom 的程式碼以及一個 RSpec 示例(測試),但請注意,沒有定義 Student 類:

class ClassRoom 
   def initialize(students) 
      @students = students 
   end
   
   def list_student_names 
      @students.map(&:name).join(',') 
   end 
end

describe ClassRoom do 
   it 'the list_student_names method should work correctly' do 
      student1 = double('student') 
      student2 = double('student') 
      
      allow(student1).to receive(:name) { 'John Smith'} 
      allow(student2).to receive(:name) { 'Jill Smith'} 
      
      cr = ClassRoom.new [student1,student2]
      expect(cr.list_student_names).to eq('John Smith,Jill Smith') 
   end 
end

執行上述程式碼時,將產生以下輸出。您計算機上的經過時間可能略有不同:

. 
Finished in 0.01 seconds (files took 0.11201 seconds to load) 
1 example, 0 failures

如您所見,使用**測試替身**允許您即使在程式碼依賴於未定義或不可用的類時也能測試程式碼。此外,這意味著當測試失敗時,您可以立即知道這是由於您自己的類中的問題造成的,而不是其他人編寫的類。

廣告
© . All rights reserved.