Say I have a method MyKlass#do_thing
that I want to call exactly once in a test (because it might change a state), and that should return true
on successful state change and false
otherwise. I want to write a spec that looks something like this:
it "Updates myvalue if condition is met" do
wojit = MyKlass.new
# ... assuming condition is met
expect { wojit.do_thing }.to change { wojit.value }.and.be true
end
But this particular approach gets an ArgumentError, because #and
expects 1 argument.
I can make it work with the following abomination:
expect { expect(wojit.do_thing).to be true }.to change { wojit.value }
But that is hiiiiideous. Am I missing something more idiomatic?
RSpec features doubles that can be used as 'stand-ins' to mock an object that's being used by another object. Doubles are useful when testing the behaviour and interaction between objects when we don't want to call the real objects - something that can take time and often has dependencies we're not concerned with.
Mocking with RSpec is done with the rspec-mocks gem. If you have rspec as a dependency in your Gemfile , you already have rspec-mocks available.
Use the allow method with the receive matcher on a test double or a real. object to tell the object to return a value (or values) in response to a given. message. Nothing happens if the message is never received.
RSpec is a testing tool for Ruby, created for behavior-driven development (BDD). It is the most frequently used testing library for Ruby in production applications. Even though it has a very rich and powerful DSL (domain-specific language), at its core it is a simple tool which you can start using rather quickly.
Another approach is just to stick the return value in a variable.
return_value = nil
expect{ return_value = wojit.do_thing }.to change{ wojit.value }
expect( return_value ).to be true
YMMV as to whether it's better or worse than nested expect
s.
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