Ruby on rails 使用RSpec double:ActiveRecord::AssociationTypeMismatch进行Rails测试:
我是RSpec的新手(对RoR也不是很有经验!) 我正在开发一个web应用程序,其中有一个课程模型。要创建新课程,我需要使用教师和学生对象 我想在课程模型上创建一个测试,为此我尝试使用instance_double来模拟老师和学生。这是我的密码Ruby on rails 使用RSpec double:ActiveRecord::AssociationTypeMismatch进行Rails测试:,ruby-on-rails,ruby,testing,activerecord,rspec,Ruby On Rails,Ruby,Testing,Activerecord,Rspec,我是RSpec的新手(对RoR也不是很有经验!) 我正在开发一个web应用程序,其中有一个课程模型。要创建新课程,我需要使用教师和学生对象 我想在课程模型上创建一个测试,为此我尝试使用instance_double来模拟老师和学生。这是我的密码 require 'rails_helper' RSpec.describe Course, type: :model do it 'can be created' do # creating the teacher john = i
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
我看到了类似的问题,所以我使用了不推荐的语法,但仍然不起作用
有什么想法吗?谢谢 如果您仍处于构建测试套件的早期阶段,我建议您实施工厂,这样您可以通过调用工厂来创建有效记录,您可以在本文中了解更多关于工厂的信息: ,然后为每个模型创建一个工厂,当您为课程模型编写规格时,请在规格之前执行以下操作:
let(:teacher) { create(:teacher) }
let(:student) { create(:student) }
let(:course) { build(:course, teacher: teacher, student: student) }
然后像这样写下你的规格:
it 'creates course successfully' do
expect(course.save).to be true
end
我真的不鼓励您使用
expect(…)。在您的规范中是有效的。Rails教程书中介绍的这种令人敬畏的地毯式轰炸方法对验证行为的描述很少,实际上只是测试测试设置本身。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
为什么不使用真正的学生和老师?如果您担心在这个测试中插入两个DB记录,您可以使用事务装置之类的东西。谢谢Sergio,我按照您的建议做了,它可以工作Hi Farah,谢谢您的帮助,我还不了解工厂!我会读你分享的文章!短期内,我用Sergio proposalyeah解决了我的问题,我要么使用像shoulda matchers这样的东西,要么根本不测试内置验证(通过提供始终满足它们的输入)@SergioTulentsev我喜欢使用无效输入来执行功能或请求规范,以立即测试验证和整个堆栈。您只需将附加值与运行规范所需的时间进行权衡。
RSpec.describe Course, type: :model do
it { is_expected.to validate_presence_of(:teacher) }
end