【问题标题】:Rspec: How to create mock associationRspec:如何创建模拟关联
【发布时间】:2015-12-19 09:37:29
【问题描述】:

我有以下课程:

class Company < ActiveRecord::Base

  validates :name,   :presence => true

  has_many :employees, :dependent => :destroy

end


class Employee < ActiveRecord::Base

  validates :first_name,     :presence => true
  validates :last_name,      :presence => true
  validates :company,        :presence => true   

  belongs_to :company

end

我正在为Employee 类编写测试,所以我正在尝试为Company 创建doubleEmployee 将使用它。

下面是我的 Rspec 的 sn-p

let(:company) { double(Company) }
let(:employee) { Employee.new(:first_name => 'Tom', :last_name => 'Smith', :company => company) }

context 'valid Employee' do

it 'will pass validation' do
  expect(employee).to be_valid
end

it 'will have no error message' do
  expect(employee.errors.count).to eq(0)
end

it 'will save employee to database' do
  expect{employee.save}.to change{Employee.count}.from(0).to(1)
end

end

我的所有 3 个测试都收到以下错误消息

ActiveRecord::AssociationTypeMismatch:
   Company(#70364315335080) expected, got RSpec::Mocks::Double(#70364252187580)

我认为我尝试创建double 的方式是错误的。你能指导我如何创建一个double of Company 可以被Employee 用作他们的关联。

我没有使用FactoryGirl

非常感谢。

【问题讨论】:

    标签: ruby-on-rails rspec


    【解决方案1】:

    没有真正的好方法可以做到这一点,而且我不确定你是否需要这样做。

    您的前两个测试本质上是在测试相同的东西(因为如果 employee 有效,employee.errors.count 将为 0,反之亦然),而您的第三个测试是测试框架/ActiveRecord,而不是任何你的代码。

    正如其他答案所提到的,Rails 在以这种方式验证时需要相同的类,所以在某些时候你必须坚持company。但是,您可以在一次测试中做到这一点,并在所有其他测试中获得您想要的速度。像这样的:

    let(:company) { Company.new }
    let(:employee) { Employee.new(:first_name => 'Tom', :last_name => 'Smith', :company => company) }
    
    context 'valid Employee' do
      it 'has valid first name' do
        employee.valid?
        expect(employee.errors.keys).not_to include :first_name
      end
    
      it 'has valid last name' do
        employee.valid?
        expect(employee.errors.keys).not_to include :last_name
      end
    
      it 'has valid company' do
        company.save!
        employee.valid?
        expect(employee.errors.keys).not_to include :company
      end
    end
    

    如果您真的想保留您的第三个测试,您可以在您的 it 块中包含 company.save!,或者禁用验证(不过,您在这一点上还要测试什么?):

    it 'will save employee to database' do
      expect{employee.save!(validate: false)}.to change{Employee.count}.from(0).to(1)
    end
    

    【讨论】:

      【解决方案2】:

      关于 SO (Rspec Mocking: ActiveRecord::AssociationTypeMismatch) 已经有类似的问题。我认为你无法摆脱使用真正的 AR 对象,因为 Rails 似乎检查了关联对象的确切类,而 double 是一些完全不同类的实例。也许您可以存根一些内部 Rails 的方法来跳过该检查,但我认为这是一个开销。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-14
        • 2015-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-09
        相关资源
        最近更新 更多