2015-12-19 2 views
3

У меня есть следующий класс:Rspec: Как создать макет ассоциации

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 класса, так что я пытаюсь создать double для Company, который будет использоваться Employee.

Ниже фрагмент кода для моего Rspec

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.

Большое спасибо.

ответ

0

Существует аналогичный вопрос о SO (Rspec Mocking: ActiveRecord::AssociationTypeMismatch). Я думаю, вы не можете уйти от использования реальных объектов AR, потому что кажется, что Rails проверяет точный класс объекта ассоциации, а double - это экземпляр некоторого совершенно другого класса. Возможно, вы могли бы заглушить некоторые внутренние методы Rails, чтобы пропустить эту проверку, но я думаю, что это накладные расходы.

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 

И если вы действительно хотите, чтобы ваш третий тест, вы можете либо включить company.save! в вашем it блоке или отключить проверку (хотя, опять же, что вы даже испытывать в этот момент?) :

it 'will save employee to database' do 
    expect{employee.save!(validate: false)}.to change{Employee.count}.from(0).to(1) 
end 
Смежные вопросы