📜  RSpec-测试双打

📅  最后修改于: 2020-12-06 10:55:55             🧑  作者: Mango


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

假设您正在为学校构建应用程序,并且有一个代表学生教室的班级,还有一个为学生服务的班级,即您有一个教室班级和一个学生班级。您需要首先为其中一个类编写代码,所以可以说,从Classroom类开始-

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

这是一个简单的类,它具有一个方法list_student_names,该方法返回以逗号分隔的学生姓名字符串。现在,我们要为该类创建测试,但是如果还没有创建Student类,该如何做呢?我们需要测试Double。

另外,如果我们有一个“虚拟”类,其行为类似于Student对象,则我们的ClassRoom测试将不依赖于Student类。我们称此测试隔离。

如果我们的ClassRoom测试不依赖于其他任何类,则当测试失败时,我们可以立即知道ClassRoom类中存在错误,而其他类则没有。请记住,在现实世界中,您可能正在构建一个需要与其他人编写的另一个类进行交互的类。

这是RSpec Doubles(模拟)变得有用的地方。我们的list_student_names方法在其@students成员变量中的每个Student对象上调用name方法。因此,我们需要一个Double来实现一个name方法。

这是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

如您所见,使用测试倍数可以使您测试代码,即使该代码依赖于未定义或不可用的类。同样,这意味着当测试失败时,您可以立即说出这是由于您的类中的问题而不是其他人编写的类而引起的。