Rspec 3.0 How to mock a method replacing the parameter but with no return value?
Solution 1
For your example, since you don't need to test the actual result of test_method
, only that puts
gets called in it passing in param
, I would just test by setting up the expectation and running the method:
class Test
def test_method(param)
puts param
end
end
describe Test do
let(:test) { Test.new }
it 'says hello via expectation' do
expect(test).to receive(:puts).with('hello')
test.test_method('hello')
end
it 'says goodbye via expectation' do
expect(test).to receive(:puts).with('goodbye')
test.test_method('goodbye')
end
end
What it seems you're attempting to do is set up a test spy on the method, but then I think you're setting up the method stub one level too high (on test_method
itself instead of the call to puts
inside test_method
). If you put the stub on the call to puts
, your tests should pass:
describe Test do
let(:test) { Test.new }
it 'says hello using a test spy' do
allow(test).to receive(:puts).with('hello')
test.test_method('hello')
expect(test).to have_received(:puts).with('hello')
end
it 'says goodbye using a test spy' do
allow(test).to receive(:puts).with('goodbye')
test.test_method('goodbye')
expect(test).to have_received(:puts).with('goodbye')
end
end
Solution 2
How to set a default value that is explained at
and_call_original
can configure a default response that can be overriden for specific args
require 'calculator'
RSpec.describe "and_call_original" do
it "can be overriden for specific arguments using #with" do
allow(Calculator).to receive(:add).and_call_original
allow(Calculator).to receive(:add).with(2, 3).and_return(-5)
expect(Calculator.add(2, 2)).to eq(4)
expect(Calculator.add(2, 3)).to eq(-5)
end
end
Source where I came to know about that can be found at https://makandracards.com/makandra/30543-rspec-only-stub-a-method-when-a-particular-argument-is-passed
Related videos on Youtube
user3060126
Updated on July 09, 2022Comments
-
user3060126 almost 2 years
I've searched a lot and just cannot figure this out although it seems basic. Here's a way simplified example of what I want to do.
Create a simple method that does something but doesn't return anything, such as:
class Test def test_method(param) puts param end test_method("hello") end
But in my rspec test I need to pass a different parameter, such as "goodbye" instead of "hello." I know this has to do with stubs and mocks, and I've looking over the documentation but can't figure it out: https://relishapp.com/rspec/rspec-mocks/v/3-0/docs/method-stubs
If I do:
@test = Test.new allow(@test).to_receive(:test_method).with("goodbye")
it tells me to stub out a default value but I can't figure out how to do it correctly.
Error message:
received :test_method with unexpected arguments expected: ("hello") got: ("goodbye") Please stub a default value first if message might be received with other args as well.
I am using rspec 3.0, and calling something like
@test.stub(:test_method)
is not allowed.
-
Andrew Marshall about 10 yearsYour error message seems to be the reverse of your stub.
-
-
user3060126 about 10 yearsThanks - this is helpful! For one, I didn't know that you could say
expect(test).to receive(:puts)
- I thought you could only call the straight method (test_method
here) so that's good to know. In the end my actual problem was more complex and I decided that I just needed to change my code to define method that did return a value, which is probably better practice anyway. And then it's easy to useallow(test).to receive(:test_method).and_return('goodbye')
. I'm sure there's another way using some of this, and it's also good to know about test spies - I hadn't come across that before.