ruby-on-rails - 使用 RSpec double 进行 Rails 测试:ActiveRecord::AssociationTypeMismatch:
问题描述
我是 RSpec 的新手(对 RoR 也不是很有经验!)
我正在开发一个有课程模型的网络应用程序。要创建新课程,我需要使用 Teacher 和 Student 对象。
我想在 Course 模型上创建一个测试,为此我尝试使用 instance_double 来模拟教师和学生。这是我的代码
require 'rails_helper'
RSpec.describe Course, type: :model do
it 'can be created' do
# creating the teacher
john = instance_double(Teacher)
allow(john).to receive(:save).and_return(true)
allow(john).to receive(:id).and_return(1)
# creating the student
francois = instance_double(Student)
allow(francois).to receive(:save).and_return(true)
allow(francois).to receive(:id).and_return(1)
# creating the course
testCourse = Course.new(teacher: john, student: francois, class_language: "EN")
# testing the course
expect(testCourse).to be_valid
end
end
我从 RSpec 得到下一个失败
1) Course can be created
Failure/Error: testCourse = Course.new(teacher: john, student: francois, class_language: "EN")
ActiveRecord::AssociationTypeMismatch:
Teacher(#70253947615480) expected, got #<Double Teacher(id: integer, email: string, encrypted_password: string, first_name: string, last_name: string, about: text, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, created_at: datetime, updated_at: datetime)> which is an instance of RSpec::Mocks::Double(#70253946301600)
# ./spec/models/course_spec.rb:16:in `block (2 levels) in <top (required)>'
Finished in 0.02549 seconds (files took 2.87 seconds to load)
1 example, 1 failure
我的理解是 ActiveRecord 错误是由于试图将 instance_double 教师和用户与期望“真正的”教师和学生关联的课程相关联而引起的。
我一直在尝试许多不同的方法,伪造 ID(请参阅我的代码),或者自己调用模型(请参阅此处的文章)
require 'student'
require 'teacher'
我看到了关于类似问题的 Stackoverflow 帖子,所以我使用了不推荐使用的语法,但它仍然不起作用。
任何想法?谢谢!
解决方案
我真的不鼓励你expect(...).to be_valid
在你的规格中使用。Rails Tutorial Book 推广的这种可怕的地毯式轰炸方法几乎没有描述验证的行为,实际上只是测试测试设置本身。IE 你真的只是在测试你的模拟,而不是你的实际应用程序!
RSpec.describe Course, type: :model do
let(:course){ Course.new }
it 'requires a teacher' do
course.valid?
expect(course.errors.details[:teacher]).to include { error: :blank }
course.teacher_id = 1 # doesn't actually have to exist
course.valid?
expect(course.errors.details[:teacher]).to_not include { error: :blank }
end
end
这写起来有点乏味,也可以使用 shoulda-matchers gem 来完成。
RSpec.describe Course, type: :model do
it { is_expected.to validate_presence_of(:teacher) }
end