How to check block is called using rspec
Asked Answered
F

2

6

I want to check whether the block is called in my function using rspec. Below is my code:

class SP
  def speak(options={},&block)
    puts "speak called" 
    block.call()
    rescue ZeroDivisionError => e
  end  
end




describe SP do
 it "testing speak functionality can receive a block" do
    sp = SP.new
    def test_func 
        a = 1
    end
    sp_mock = double(sp)
    expect(sp_mock).to receive(:speak).with(test_func)
    sp.speak(test_func)
 end  
end 

Below is my error:

SP testing speak functionality can receive a block
     Failure/Error: block.call()

     NoMethodError:
       undefined method `call' for nil:NilClass
     # ./test.rb:9:in `speak'
     # ./test.rb:25:in `block (2 levels) in <top (required)>'

Could you please help. I spent lots of time in that.

Femme answered 16/6, 2017 at 21:13 Comment(0)
G
12

You have to use one of RSpec's yield matcher:

describe SP do
  it "testing speak functionality can receive a block" do
    sp = SP.new
    expect { |b| sp.speak(&b) }.to yield_control
  end
end
Glosseme answered 16/6, 2017 at 21:26 Comment(0)
W
4

I think Stefan provided the best answer. However I wanted to point out that you should be testing the behaviour of the code instead of implementation details.

describe SP do
  it "testing speak functionality can receive a block" do
    sp = SP.new
    called = false
    test_func = -> () { called = true }

    sp.speak(&test_func)

    expect(called).to eql(true)
  end  
end
Wisniewski answered 16/6, 2017 at 21:50 Comment(2)
That's what yield_control does, isn't it?Glosseme
@Glosseme It depends on what you actually want to test. In this case .yield_with_no_args would be the most specific test. But since SP#speak behaves differently depending on the passed block, you should cover those cases too. In the test setup the passed block should raise ZeroDivisionError.Wisniewski

© 2022 - 2024 — McMap. All rights reserved.