`stub` for Class in rspec2 - ruby

describe SomeThing do
before :all do
# ...
FooClass.stub(:fooMethod).with('a').and_return("something")
end
end
Worked cool with rspec 1.
I've updated to rspec 2, and this is what i'm receiving for this line now:
Failure/Error:
FooClass.stub(:fooMethod).with('a').and_return("something")
NoMethodError:
undefined method `stub' for FooClass::Class
The rspec api but says: Person.stub(:find) { person }
What am i missing?

Is this inside an it or before block?
Stubs are not supported in before :all blocks. Stubs and mocks get cleared after each example. You can read more about this here. Change the before :all do to before do and this should work.

Related

Rspec 3.0 How to mock a method replacing the parameter but with no return value?

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

user must_send with a method that calls super in minitest

Lets say I have the following module:
module SillyDemo
class Monkey
def screech(sound)
sound
end
end
class Ape < Monkey
def process(sound)
sound
end
def screech(sound)
process(sound)
super
sound
end
end
end
And then the following minitest:
require_relative 'sillydemo'
require "minitest/spec"
require "minitest/autorun"
describe "Ape" do
before do
#ape = Ape.new
#screech = "YEEEEEEE"
end
it "screeches" do
#ape.screech(#screech)
must_send [#ape, :process, #screech]
must_send [#ape, :super, #screech]
end
end
This errors out with:
NoMethodError: undefined method `super' for #<SillyDemo::Ape:0x007feeb10943c0>
(eval):4:in `must_send'
I have also tried:
must_send [#ape, :"SillyDemo::Monkey.screech", #screech]
which errors out with:
NoMethodError: undefined method `SillyDemo::Ape.run' for #<SillyDemo::Ape:0x007fc5a1874e20>
(eval):4:in `must_send'
My question is, how can I use minitest to test a call to super?
In Ruby super is a keyword, not a method. Also, the must_send expectation isn't verifying that the method was called, it just verifies that the return value from the method is truthy.
http://www.ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest/Expectations.html#method-i-must_send
http://www.ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest/Assertions.html#method-i-assert_send
Mocks are usually used to verify that a method was called. However, Minitest::Mock doesn't allow for this type of check very easily by design. Here is how you can do this though.
it "screeches" do
# 1) Create mock
sound_mock = Minitest::Mock.new
sound_mock.expect :process, true, [String]
# 2) Place mock
#ape.instance_exec(sound_mock) do |sound_mock|
#mock = sound_mock
def process sound
#mock.process sound
end
end
# 3) Verify mock was called
#ape.screech(#screech)
sound_mock.verify
end
Pretty ugly, right? This is by design. Sort of like syntactic vinegar. The reason is that this use of mocks isn't very informative. It is checking the implementation of the code. You would like to be able to refactor the code without changing behavior and have the tests continue to pass. However, this test will very likely fail when the implementation is changed. To discourage folks from making this kind of mistake it was decided by the Minitest authors to keep this type of check difficult.
Other mocking libraries such as RR or Mocha make this type of check much easier.

Rspec any_instance.stub raises undefined method `any_instance_recorder_for' for nil:NilClass exception

Here is the class that I'm testing contained in Foo.rb:
class Foo
def bar
return 2
end
end
Here is the my test contained in Foo_spec.rb:
require "./Foo.rb"
describe "Foo" do
before(:all) do
puts "#{Foo == nil}"
Foo.any_instance.stub(:bar).and_return(1)
end
it "should pass this" do
f = Foo.new
f.bar.should eq 1
end
end
I am getting the following output:
false
F
Failures:
1) Foo Should pass this
Failure/Error: Foo.any_instance.stub(:bar).and_return(1)
NoMethodError:
undefined method `any_instance_recorder_for' for nil:NilClass
# ./Foo_spec.rb:6:in `block (2 levels) in <top (required)>'
Finished in 0 seconds
1 example, 1 failure
Failed examples:
rspec ./Foo_spec.rb:9 # Foo Should pass this
I've consulted the doc and the example given is passing on my machine (so it isn't a problem with the rspec code), but it isn't giving me any information on what I might be doing wrong. The error message is also quite confusing as it's telling me not to call .any_instance on a nil:NilClass, but as I proved with my output, Foo isn't nil. How am I supposed to call .any_instance.stub on my custom object?
I'm using Ruby 1.9.3 and rspec 2.14.5.
You should use before(:each) for stubbing.
Stubs in before(:all) are not supported. The reason is that all stubs and mocks get cleared out after each example, so any stub that is set in before(:all) would work in the first example that happens to run in that group, but not for any others.
rspec-mocks readme
From Rspec 3 any_instance is not defined anymore.
Now use:
allow_any_instance_of(Foo).to receive(:bar).and_return(1)
Source for this and older versions:
https://makandracards.com/makandra/2561-stub-methods-on-any-instance-of-a-class-in-rspec-1-and-rspec-2
Updating rspec worked for me. You can do it using the following command:
bundle update rspec

Why isn't this simple Ruby code working in HAML?

If I run this simple Ruby code regularly, it works fine:
class String
def add_two
self + "2"
end
end
puts "hello".add_two
It prints "hello2" as it should. But this fails:
:ruby
class String
def add_two
self + "2"
end
end
puts "hello".add_two
This code produces an error:
NoMethodError at /
undefined method `add_two' for "hello":String
Any ideas what's wrong?
(Not sure if it matters, but I'm using HAML with Sinatra, which is running on Apache with the Passenger module.)
I would suggest that String is in another namespace and therefor another class.
What happens with that?
class ::String
I put your code as is into one of my Haml views in a Rails app and I got a different error to you:
SyntaxError at /
class definition in method body
So I wondered whether it was Haml's :ruby filter that was complaining, but since it "Parses the filtered text with the normal Ruby interpreter", it seemed unlikely. So, I searched for more info about the error and found references (see below) that led me to this, which works (but, really, should never be used):
:ruby
String.module_eval do
def add_two
self + "2"
end
end
puts "hello".add_two
References:
Class inside a Method Body
Class (Re)definition in Method Body

Does should_receive do something I don't expect?

Consider the following two trivial models:
class Iq
def score
#Some Irrelevant Code
end
end
class Person
def iq_score
Iq.new(self).score #error here
end
end
And the following Rspec test:
describe "#iq_score" do
let(:person) { Person.new }
it "creates an instance of Iq with the person" do
Iq.should_receive(:new).with(person)
Iq.any_instance.stub(:score).and_return(100.0)
person.iq_score
end
end
When I run this test (or, rather, an analogous one), it appears the stub has not worked:
Failure/Error: person.iq_score
NoMethodError:
undefined method `iq_score' for nil:NilClass
The failure, as you might guess, is on the line marked "error here" above. When the should_receive line is commented out, this error disappears. What's going on?
Since RSpec has extended stubber functionality, now following way is correct:
Iq.should_receive(:new).with(person).and_call_original
It will (1) check expectation (2) return control to original function, not just return nil.
You're stubbing away the initializer:
Iq.should_receive(:new).with(person)
returns nil, so Iq.new is nil. To fix, just do this:
Iq.should_receive(:new).with(person).and_return(mock('iq', :iq_score => 34))
person.iq_score.should == 34 // assert it is really the mock you get

Resources