Let's say I have classes Car and Mechanic. Car has "run" method. Mechanic requires Car for some reason. Then I write RSpec specs. In mechanic I define a fake clas like this:
class Car; end
and later stub the method that mechanic uses on it. All works fine if I run tests seperately. But when I run both tests together (rspec spec/directory/) my Mechanic specs use real Car class.
So. I guess this is because ruby classes are "open" and I already loaded the class once for Car specs. But is there a better way to do this? What are best practices for this kind of situations? Does this mean my code needs some improvements cause it's probably tightly coupled?
I made a quick demo in github: https://github.com/depy/RspecTest
This fake class wont work since Ruby Classes are open.
One approach you could be using is to use let to initialize the objects the way you want, and if needed work with the relationship on a before block. Stubs are welcome as well inside the before blocks. =p
Hope this helps you!
I think what you need is two-layer testing:
Given the code as follows:
class Car
end
class Mechanic
def fix(car)
# do something here
end
end
For unit specs I would stub the dependencies, for example:
describe Mechanic do
let(:mechanic) { described_class.new }
let(:car) { stub(stubbed_method_on_car: 14) } # Or just OpenStruct.new(stubbed_method_on_car: 14)
it 'does some stuff' do
mechanic.fix(car).should eq true
end
end
For integration specs I would do this:
describe Mechanic do
let(:mechanic) { FactoryGirl.create(:mechanic) }
let(:car) { FactoryGirl.create(:car) }
it 'does some stuff' do
mechanic.fix(car).should eq true
end
end
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