I have following class:
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
I am writing test for Employee
class, so I am trying to create double
for Company
which will be used by Employee
.
Below is the snippet for my 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
I am getting following error message for all of my 3 tests
ActiveRecord::AssociationTypeMismatch:
Company(#70364315335080) expected, got RSpec::Mocks::Double(#70364252187580)
I think the way I am trying to create double
is wrong. Can you please guide me how to create a double of Company
which can be used by Employee
as their association.
I am not using FactoryGirl
.
Thanks a lot.
There is not really a great way to do this, and I'm not sure you need to anyway.
Your first two tests are essentially testing the same thing (since if the employee
is valid, employee.errors.count
will be 0, and vice versa), while your third test is testing the framework/ActiveRecord, and not any of your code.
As other answers have mentioned, Rails wants the same classes when validating in that way, so at some point you'll have to persist the company
. However, you can do that in just one test and get the speed you want in all the others. Something like this:
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
And if you really want to keep your third test, you can either include company.save!
in your it
block, or disable validation (though, again, what are you even testing at that point?):
it 'will save employee to database' do
expect{employee.save!(validate: false)}.to change{Employee.count}.from(0).to(1)
end
There is already similar question on SO (Rspec Mocking: ActiveRecord::AssociationTypeMismatch). I think you can't get away from using real AR objects 'cause it seems that Rails checks exact class of association object and double is an instance of some absolutely different class. Maybe you could stub some inner Rails' methods to skip that check but I think it's an overhead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With