Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you simultaneously test a state change and a return value in RSpec?

Tags:

ruby

rspec

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?

like image 663
Arepo Avatar asked Mar 13 '18 12:03

Arepo


People also ask

What is RSpec double?

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.

How do I mock a method in RSpec?

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.

What is allow in RSpec?

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.

What type of testing is RSpec?

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.


1 Answers

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 expects.

like image 161
rampion Avatar answered Oct 04 '22 04:10

rampion