- RSpec 教程
- RSpec - 首页
- RSpec - 简介
- RSpec - 基本语法
- RSpec - 编写规范
- RSpec - 匹配器
- RSpec - 测试替身
- RSpec - 存根
- RSpec - 钩子
- RSpec - 标签
- RSpec - 主题
- RSpec - 辅助函数
- RSpec - 元数据
- RSpec - 过滤
- RSpec - 期望
- RSpec 资源
- RSpec - 快速指南
- RSpec - 有用资源
- RSpec - 讨论
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
如您所见,使用**测试替身**允许您即使在代码依赖于未定义或不可用的类时也能测试代码。此外,这意味着当测试失败时,您可以立即知道这是由于您自己的类中的问题造成的,而不是其他人编写的类。