RSpec – 测试双打

RSpec – 测试双打


在本章中,我们将讨论 RSpec Doubles,也称为 RSpec Mocks。Double 是一个可以“代替”另一个对象的对象。您可能想知道这究竟意味着什么以及为什么需要一个。

假设您正在为一所学校构建一个应用程序,并且您有一个代表一个学生教室的类和另一个代表学生的类,即您有一个 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

如您所见,使用测试替身可以让您测试代码,即使它依赖于未定义或不可用的类。此外,这意味着当测试失败时,您可以立即判断这是因为您班级的问题而不是其他人编写的班级。

觉得文章有用?

点个广告表达一下你的爱意吧 !😁