rubyrspec

Can you simultaneously test a state change and a return value in 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?


Solution

  • This question is 6y old but still relevant, so I wanted to update with latest preferred solution for this problem. subject evaluation is cached. This allows you first check the change effect, and on the next line check return value without it running twice. Basically same as @rampion suggested just more readable.

    subject(:do_thing) { wojit.do_thing }
    
    let(:wojit) { MyKlass.new }
    
    it "changes and returns true" do
      expect{ do_thing }.to change(wojit, :value)
      expect( do_thing ).to be(true)
    end