rspec / rspec-mocks Goto Github PK
View Code? Open in Web Editor NEWRSpec's 'test double' framework, with support for stubbing and mocking
Home Page: https://rspec.info
License: MIT License
RSpec's 'test double' framework, with support for stubbing and mocking
Home Page: https://rspec.info
License: MIT License
I ran into this when working on #10
it "raises an error if 'with' follows 'and_return'" do
lambda do
foo = ""
foo.should_receive(:foo).and_return(1).with("1")
foo.foo('')
end.should raise_error(NoMethodError)
end
instead of passing this produces
().foo(any args)
expected: 1 time
received: 0 times
Clearly, the with
is being ignored entirely. Interestingly, replacing should_receive
with stub
makes this test pass.
It works already in stubbed_message_expectations_spec.rb
Removed in
http://github.com/txus/rspec-mocks/commit/20f525189e89733a4202230cf753c5f4245dd54f
Defining stubs on any instance of an object doesn't work when using the stub!
method. This scenario fails:
Scenario: simple any_instance stub with a single return value using the stub! alias
Given a file named "example_spec.rb" with:
"""
describe "any_instance.stub!" do
it "returns the specified value on any instance of the class" do
Object.any_instance.stub!(:foo).and_return(:return_value)
o = Object.new
o.foo.should eq(:return_value)
end
end
"""
When I run `rspec example_spec.rb`
Then the examples should all pass
Example:
@obj = Object.new
@obj.should_receive(:to_s).at_least(:once) {"testing"}
@obj.to_s.should == "testing"
Upper test fails. It works if I modify the expectation line like that, but doesn't read right:
@obj.should_receive(:to_s).at_least(:once).times {"testing"}
No better way to describe this then:
http://floehopper.lighthouseapp.com/projects/22289-mocha/tickets/70
Ran into this while trying to run specs for Formtastic in 1.9.2. Problem with just stubbing it is it then breaks other tests because rails uses respond_to?(:to_ary) internally which breaks other tests in formtastic...
Rspec response:
Mock "user" received unexpected message :to_ary with (no args)
# ./lib/formtastic.rb:575:in flatten' # ./lib/formtastic.rb:575:in
inputs_for_nested_attributes'
# ./lib/formtastic.rb:280:in inputs' # ./spec/inputs_spec.rb:439:in
block (6 levels) in <top (required)>'
# ./lib/formtastic.rb:1927:in block in semantic_form_for' # ./lib/formtastic.rb:1892:in
with_custom_field_error_proc'
# ./lib/formtastic.rb:1926:in semantic_form_for' # ./spec/inputs_spec.rb:438:in
block (5 levels) in <top (required)>'
Let me know what else is needed...
Inspired in the solution for yaml serialization :)
It is a bit monkey-patchesque but I think it is justified, because the Marshal extension is only loaded when Serialization module is.
Patched in
http://github.com/txus/rspec-mocks/commit/b003364efd3a6fbac6b431ccb3b78f5d0d8641d4
Currently, if I try to specify both:
obj.should_receive(:message).with(...something...)
obj.should_receive(:message).with(...something...else...)
and
obj.should_receive(:message).twice
the latter expectation is reported unmet.
I have found a workaround which is obj.should_receive(:message).never
instead of ....twice
(note that for a reason unfortunately unknown obj.should_receive(:message).never
is not the same as obj.should_not_receive(:message)
here), but it leads to specs slightly less comprehensible than I would like them to be.
I only just noticed this when I added a build of rspec-mocks on JRuby to our CI instance.
~/Work/Rspec/rspec-mocks (master)λ rake spec jruby-1.6.1@rspecmocks
(in /Users/sidu/Work/Rspec/rspec-mocks)
zsh:1: no matches found: bin/*
zsh:1: no matches found: bin/*
zsh:1: no matches found: spec/*
zsh:1: no matches found: bin/*
zsh:1: no matches found: bin/*
/Users/sidu/.rvm/rubies/jruby-1.6.1/bin/jruby -S bundle exec rspec --color ./spec/rspec/mocks_spec.rb ./spec/rspec/mocks/and_yield_spec.rb ./spec/rspec/mocks/any_instance_spec.rb ./spec/rspec/mocks/any_number_of_times_spec.rb ./spec/rspec/mocks/argument_expectation_spec.rb ./spec/rspec/mocks/at_least_spec.rb ./spec/rspec/mocks/at_most_spec.rb ./spec/rspec/mocks/block_return_value_spec.rb ./spec/rspec/mocks/bug_report_10260_spec.rb ./spec/rspec/mocks/bug_report_10263_spec.rb ./spec/rspec/mocks/bug_report_11545_spec.rb ./spec/rspec/mocks/bug_report_496_spec.rb ./spec/rspec/mocks/bug_report_600_spec.rb ./spec/rspec/mocks/bug_report_7611_spec.rb ./spec/rspec/mocks/bug_report_8165_spec.rb ./spec/rspec/mocks/bug_report_830_spec.rb ./spec/rspec/mocks/bug_report_957_spec.rb ./spec/rspec/mocks/double_spec.rb ./spec/rspec/mocks/failing_argument_matchers_spec.rb ./spec/rspec/mocks/hash_including_matcher_spec.rb ./spec/rspec/mocks/hash_not_including_matcher_spec.rb ./spec/rspec/mocks/mock_ordering_spec.rb ./spec/rspec/mocks/mock_space_spec.rb ./spec/rspec/mocks/mock_spec.rb ./spec/rspec/mocks/multiple_return_value_spec.rb ./spec/rspec/mocks/nil_expectation_warning_spec.rb ./spec/rspec/mocks/null_object_mock_spec.rb ./spec/rspec/mocks/once_counts_spec.rb ./spec/rspec/mocks/options_hash_spec.rb ./spec/rspec/mocks/partial_mock_spec.rb ./spec/rspec/mocks/partial_mock_using_mocks_directly_spec.rb ./spec/rspec/mocks/passing_argument_matchers_spec.rb ./spec/rspec/mocks/precise_counts_spec.rb ./spec/rspec/mocks/record_messages_spec.rb ./spec/rspec/mocks/serialization_spec.rb ./spec/rspec/mocks/stash_spec.rb ./spec/rspec/mocks/stub_chain_spec.rb ./spec/rspec/mocks/stub_implementation_spec.rb ./spec/rspec/mocks/stub_spec.rb ./spec/rspec/mocks/stubbed_message_expectations_spec.rb ./spec/rspec/mocks/to_ary_spec.rb ./spec/rspec/mocks/twice_counts_spec.rb
zsh:1: no matches found: bin/*
zsh:1: no matches found: bin/*
zsh:1: no matches found: spec/*
zsh:1: no matches found: bin/*
Run filtered excluding {:ruby=>#<Proc:/Users/sidu/Work/Rspec/rspec-mocks/spec/spec_helper.rb:42>}
................**....................................................................................................................................................................................................................................................................................................................................................................................................................................
Pending:
#any_instance invocation order#should_receive raises an error if 'with' follows 'and_return'
# see Github issue #42
# ./spec/rspec/mocks/any_instance_spec.rb:40
#any_instance invocation order#should_receive raises an error if 'with' follows 'and_raise'
# see Github issue #42
# ./spec/rspec/mocks/any_instance_spec.rb:45
Finished in 3.94 seconds
438 examples, 0 failures, 2 pending
rake aborted!
ruby -S bundle exec rspec --color ./spec/rspec/mocks_spec.rb ./spec/rspec/mocks/and_yield_spec.rb ./spec/rspec/mocks/any_instance_spec.rb ./spec/rspec/mocks/any_number_of_times_spec.rb ./spec/rspec/mocks/argument_expectation_spec.rb ./spec/rspec/mocks/at_least_spec.rb ./spec/rspec/mocks/at_most_spec.rb ./spec/rspec/mocks/block_return_value_spec.rb ./spec/rspec/mocks/bug_report_10260_spec.rb ./spec/rspec/mocks/bug_report_10263_spec.rb ./spec/rspec/mocks/bug_report_11545_spec.rb ./spec/rspec/mocks/bug_report_496_spec.rb ./spec/rspec/mocks/bug_report_600_spec.rb ./spec/rspec/mocks/bug_report_7611_spec.rb ./spec/rspec/mocks/bug_report_8165_spec.rb ./spec/rspec/mocks/bug_report_830_spec.rb ./spec/rspec/mocks/bug_report_957_spec.rb ./spec/rspec/mocks/double_spec.rb ./spec/rspec/mocks/failing_argument_matchers_spec.rb ./spec/rspec/mocks/hash_including_matcher_spec.rb ./spec/rspec/mocks/hash_not_including_matcher_spec.rb ./spec/rspec/mocks/mock_ordering_spec.rb ./spec/rspec/mocks/mock_space_spec.rb ./spec/rspec/mocks/mock_spec.rb ./spec/rspec/mocks/multiple_return_value_spec.rb ./spec/rspec/mocks/nil_expectation_warning_spec.rb ./spec/rspec/mocks/null_object_mock_spec.rb ./spec/rspec/mocks/once_counts_spec.rb ./spec/rspec/mocks/options_hash_spec.rb ./spec/rspec/mocks/partial_mock_spec.rb ./spec/rspec/mocks/partial_mock_using_mocks_directly_spec.rb ./spec/rspec/mocks/passing_argument_matchers_spec.rb ./spec/rspec/mocks/precise_counts_spec.rb ./spec/rspec/mocks/record_messages_spec.rb ./spec/rspec/mocks/serialization_spec.rb ./spec/rspec/mocks/stash_spec.rb ./spec/rspec/mocks/stub_chain_spec.rb ./spec/rspec/mocks/stub_implementation_spec.rb ./spec/rspec/mocks/stub_spec.rb ./spec/rspec/mocks/stubbed_message_expectations_spec.rb ./spec/rspec/mocks/to_ary_spec.rb ./spec/rspec/mocks/twice_counts_spec.rb failed
(See full trace by running task with --trace)
I have a spec where I do
User.any_instance.stub_chain(:challenges, :won){
[ @challenge1, @challenge2 ]
}
but I get the error
undefined method `playback!' for nil:NilClass
/Users/bradphelan/.rvm/gems/ruby-1.9.2-p180@mysugrapp/gems/activesupport-3.1.0.rc5/lib/active_support/whiny_nil.rb:48:in `method_missing'
/Users/bradphelan/.rvm/gems/ruby-1.9.2-p180@mysugrapp/gems/rspec-mocks-2.6.0/lib/rspec/mocks/any_instance.rb:134:in `playback!'
/Users/bradphelan/.rvm/gems/ruby-1.9.2-p180@mysugrapp/gems/rspec-mocks-2.6.0/lib/rspec/mocks/any_instance.rb:221:in `challenges'
/Users/bradphelan/workspace/mysugr/mysugrapp/app/controllers/challenges_controller.rb:34:in `index_won'
a bit of digging and I modified the code in any_instance to look like
----------------------
/Users/bradphelan/.rvm/gems/ruby-1.9.2-p180@mysugrapp/gems/rspec-mocks-2.6.0/lib/rspec/mocks/any_instance.rb
----------------------
129 def playback!(instance, method_name)
130 RSpec::Mocks::space.add(instance)
131 puts 'BPH'
132 pp @message_chains
133 pp method_name
134 @message_chains[method_name].playback!(instance)
135 @played_methods[method_name] = instance
136 received_expected_message!(method_name) if has_expectation?(method_name)
137 end
The output at this point in the code was
BPH
{"challenges"=>
#<RSpec::Mocks::AnyInstance::StubChain:0x00000106718020
@invocation_order=
{:stub=>[nil],
:with=>[:stub],
:and_return=>[:with, :stub],
:and_raise=>[:with, :stub],
:and_yield=>[:with, :stub]},
@messages=
[[[:stub, "challenges"],
#<Proc:0x00000106718c50@/Users/bradphelan/.rvm/gems/ruby-1.9.2-p180@mysugrapp/gems/rspec-mocks-2.6.0/lib/rspec/mocks/methods.rb:45>]]>}
:challenges
It seems the key in the hash is a string "challenges" but the hash is being indexed by the symbol :challenges and
returns null and therefore the crash.
I modified the source code to
def playback!(instance, method_name)
RSpec::Mocks::space.add(instance)
method_name = method_name.to_s
@message_chains[method_name].playback!(instance)
@played_methods[method_name] = instance
received_expected_message!(method_name) if has_expectation?(method_name)
end
and now my spec works
unstub / unstub! is not available in rspec-mocks 2.0.0.beta7. Since it's rather handy to be able to remove som stubs mid-test I would like to see it implemented in rspec 2.0
it 'receives empty hash' do
a = Object.new
def a.x(arg={}); end
a.should_receive(:x).with({})
a.x(nil)
end
The received error message is a bit confusing:
Failure/Error: a.x(nil)
#<Object:0x000000032da9a8> received :x with unexpected arguments
expected: ({})
got: ({})
Hi David,
I often find myself declaring a bunch of test doubles with no stubs on them, just dummy objects I can pass around to isolate the spec. An example:
it 'does something' do
logger = double :logger
foo = double :foo
bar = double :bar
# Pass these objects around
...
end
I'm wondering whether it would be useful to declare these dummy objects in bulk, like this:
it 'does something' do
doubles :logger, :foo, :bar #sets the variables logger, foo and bar to dummy test doubles
...
end
I'm thinking it might have more sense to move this idiom +outside+ the examples:
describe 'some example group' do
doubles :logger, :foo, :bar #would be equivalent to let(:logger) { double :logger }, let(:foo)...
it 'does something' do
# here logger, foo, and bar are available in every example inside this context block
end
Do you have any feedback on these? I don't think it makes the examples any less readable, so it might be useful to avoid cluttering examples with cumbersome dummy object declaration. I'd be happy to implement it if it goes through. What do you think?
If you write obj.stub(:foo).with(1) {5} with the intention that 5 will be the return value, you'll likely be surprised when you discover that the block is also being used as an argument matcher and that the code will match invocation like obj.foo(2) etc.
As per this RSpec 1 ticket, return values are no longer returned when setting an expectation on a stubbed method with args.
Here is a failing example.
Spec:
class MyClass def initialize(dependency) @dependency = dependency end def calculate_value @dependency.foo end end describe MyClass, '#calculate_value' do let(:dependency) { Object.new } subject { MyClass.new(dependency) } context 'when dependency.foo returns :bar' do before(:each) { dependency.stub(:foo).and_return(:bar) } it 'returns :bar' do subject.calculate_value.should == :bar end it 'memoizes the value so dependency.foo is not invoked multiple times' do dependency.should_receive(:foo).once 3.times { subject.calculate_value } end end end
These specs pass:
$ rspec rspec_example.rb .. Finished in 0.00199 seconds 2 examples, 0 failures
...but the 2nd example should fail. If I comment out the before(:each)
, then it properly fails.
Running rake for rspec-mocks against Jruby-1.6.0 on OSX against ef127a5 has nil_expectation_warning_spec.rb fail with the trace given at the end of this ticket.
The failure seems to be occurring because jruby returns a failure trace with
Called from #{FILE}:#{LINE+3}:in (class Mocks)' instead of what CRuby returns which is Called from #{__FILE__}:#{__LINE__+3}(:in
block (2 levels) in module:Mocks
These strings are generated by caller[4]
so this might actually be a JRuby issue (which I will check and confirm).
Trace:
1) an expectation set on nil issues a warning with file and line number information
Failure/Error: nil.should_receive(:foo)
Kernel received :warn with unexpected arguments
expected: (/An expectation of :foo was set on nil. Called from /Users/sidu/Work/Rspec/rspec-mocks/spec/rspec/mocks/nil_expectation_warning_spec.rb:21(:in block \(2 levels\) in <module:Mocks>')?. Use allow_message_expectations_on_nil to disable warnings./) got: ("An expectation of :foo was set on nil. Called from /Users/sidu/Work/Rspec/rspec-mocks/spec/rspec/mocks/nil_expectation_warning_spec.rb:21:in
(class Mocks)'. Use allow_message_expectations_on_nil to disable warnings.")
# ./spec/rspec/mocks/nil_expectation_warning_spec.rb:21:in (class Mocks)' # org/jruby/RubyKernel.java:2007:in
instance_eval'
# org/jruby/RubyArray.java:2306:in collect' # org/jruby/RubyArray.java:2306:in
collect'
I'm trying to set up a spec like this:
class Calc
end
context "any_instance with receiver count expectation" do
before do
Calc.any_instance.should_receive(:add).twice
end
it 'should work with multiple instances' do
Calc.new.add(1,2)
Calc.new.add(2,3)
end
This doesn't work, it generates an error:
RSpec::Mocks::MockExpectationError: The message 'add' was received by #<Calc:0x884cdc8> but has already been received by #<Calc:0x884f9d8>
I'm concluding that when using a receiver count expectation any_instance
is specific to a given instance, counter to the assumption that any_instance
really should work with any instance.
What I actually want to do is to be able to define multiple argument expectations with this, along the lines of:
Calc.any_instance.should_receive(:add).with(1,2).and_return(3)
Calc.any_instance.should_receive(:add).with(2,3).and_return(5)
That totally breaks down. The simple calculator example here is for illustration only, my actual issue is more complex and I can't easily compute the return value, but have to rely on table look-ups. In other words, I've not found a suitable work-around and I really need this behavior as described above, if it's supposed to be supported (which I'm not sure of).
I don't know if it matters: I'm doing this with Rails 3, RSpec 2.6, and Ree Ruby 1.8.7
I know that mocks defined to be "as_null_object" are supposed to swallow all messages they receive, but that can lead to some tests succeeding when they in fact should fail.
In particular, the "should_*" expectations should at least trigger a warning that the code has a potential misspelling. This is a "nice to have" feature for programmers (like me) who sometimes mispel wrds and mehtods sent to mocks.
Here is some example code.
require 'rubygems' require 'rspec' class Foo; end describe Foo do it "should give a warning on this test that 'should_recieve' is a potential misspelling" do m = mock.as_null_object m.should_recieve(:new) m.new end end
I'd expect this to pass (using rspec 2.5.1)
describe 'stub_chain' do it "returns expected value from two chains with hash" do subject = Object.new subject.stub_chain(:msg1, :msg2 => :first) subject.stub_chain(:msg1, :msg3 => :second) subject.msg1.msg2.should equal(:first) subject.msg1.msg3.should equal(:second) end end
But it doesn't - subject.msg1.msg3 returns nil
test_model.rb
class TestModel
def meth
raise 'meth called'
end
end
test_model_spec.rb
require 'spec_helper'
describe TestModel do
before do
TestModel.any_instance.stub(:meth)
end
it 'should be stubbed' do
lambda { TestModel.new.meth }.should_not raise_error
end
it 'should be able to unstub' do
TestModel.any_instance.unstub(:meth)
lambda { TestModel.new.meth }.should raise_error
end
end
rspec test_model_spec.rb -f d
TestModel
should be stubbed
should be able to unstub (FAILED - 1)
Failures:
1) TestModel should be able to unstub
Failure/Error: TestModel.any_instance.unstub(:meth)
The method `meth` was not stubbed or was already unstubbed
# test_model_spec.rb:13
PS. I think we're all robots here speaking code&specs :)
As discussed on the mailing list, I've started the work on adding an undefined method stub report in a branch. I've got things to the point where I've recorded all the various bits of info, and now we just need to add the code to print the report. Since there wasn't much feedback from others, I figured it'd be easiest to nail down the details here, but we can take the conversation back to the mailing list if you'd prefer.
For reference, here's the current documentation output for the UndefinedMethodDouble specs:
RSpec::Mocks::UndefinedMethodDouble when recording is disabled a stub of a previously undefined method is not recorded a mock of a previously undefined method is not recorded when recording is enabled a stub of a previously defined method is not recorded a stub of a previously undefined method is not recorded when the method is defined before the invocation when the method double is defined and invoked once records the stubed object records the stubed method records the invocation records the definition for a pure mock object is not recorded for a pure stub object is not recorded for a pure double object is not recorded when the method double is defined once and invoked twice records only a single stubed object records only a single stubed method records only a single definition records each invocation when the method double is defined twice and invoked once records only a single stubed object records only a single stubed method records each definition records only a single invocation a mock of a previously defined method is not recorded a mock of a previously undefined method is not recorded when the method is defined before the invocation when the method double is defined and invoked once records the mocked object records the mocked method records the invocation records the definition for a pure mock object is not recorded for a pure stub object is not recorded for a pure double object is not recorded when the method double is defined once and invoked twice records only a single mocked object records only a single mocked method records only a single definition records each invocation when the method double is defined twice and invoked once records only a single mocked object records only a single mocked method records each definition records only a single invocation
David, at this point, I could use some input from you.
<pre>
block.setup_mocks_for_rspec
, verify_mocks_for_rspec
and teardown_mocks_for_rspec
), we can add an (optional) fourth method: print_summary_for_rspec
. For now, rspec-mocks would be the only one to actually do anything here, but in the future if any of the other mocking libraries provide similar functionality, they'd have a place to hook in.BTW, I'm not 100% happy with my naming of things (particularly UndefinedMethodDouble
), so please make suggestions for anything you think could be organized or named better!
Rspec-mocks won't automatically extend its example methods once loaded, since it relies on an explicit RSpec::Mocks::setup(self) method, so that when RSpec is configured with other mocking frameworks, rspec-mocks won't have their extensions loaded (more information on http://github.com/rspec/rspec-mocks/issues/closed/#issue/7)
The thing is that RSpec::Mocks::setup(includer) includes its methods in includer's eigenclass, rather than its regular class (http://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks.rb#L181), so that the only way to include rspec-mocks as instance methods in Test::Unit::TestCases is to call the setup from inside an instance method of the test case itself:
class SomeTest < Test::Unit::TestCase
def test_whatever
RSpec::Mocks::setup(self)
something.should_receive(:something_else)
end
end
This is not very comfortable. I've tried to force the setup to include its instance methods in the original Test::Unit::TestCase, with no luck. Any thoughts on how could this be achieved?
I have been testing code that uses Process.fork. Specifically I'd like to test that a certain method is called when the parent process receives a signal. Obviously should_receive won't work because once I call Process.fork, the memory is no longer shared. It is possible to communicate with a named pipe or a temp file. Here is an example using a temp file.
context "when it receives a SIGINT" do
it "should call #stop! on its worker" do
file = Tempfile.new("stop-stub-#{subject.worker.object_id}")
# Make #stop! write out to a file so we can verify that it was called
# even though it is run in a separate process.
subject.worker.stub(:stop!) do |*args|
msg = args.inspect
file.puts msg
Rails.logger.info "#stop! called on Worker with object_id; args: #{args.inspect}"
end
pid = Process.fork do
subject.start!
end
sleep 0.1
Process.kill('INT', pid)
file.rewind
lines = file.readlines
lines.size.should == 1 # Called exactly once.
lines[0].should == "[]\n" # Called with no arguments.
end
end
obviously it would be a lot nicer if I could do something like this:
context "when it receives a SIGINT" do
it "should call #stop! on its worker" do
subject.worker.should_receive_in_child_process(:stop!)
pid = Process.fork do
subject.start!
end
sleep 0.1
Process.kill('INT', pid)
end
end
I am writing some test helpers for a gem, so that users of the gem can easily stub out the gem behavior in the (controller) specs. In other words, somewhere in the example there would be something along the lines of
it "should do the right thing" do
stub_my_gem
get :my_action
result.should be_what_we_want
end
I would like to transparently be able to support all the mocking frameworks supported by RSpec, but in order to do that I would need to have all implementations of MockFrameworkAdapter to define a method name which would return the same symbol passed to +mock_with+ and allow my test helpers to create and setup the correct stubs for the given framework:
case RSpec.configuration.settings[:mock_framework].name
when :rr
stub_with_rr
when :rspec
stub_with_rspec
#and so forth
end
The change is fairly easy, and I could take care it, but before starting forking, patching etc... I would like to know whether I am on the right track or is there already an easier way to get the currently configured mock_framework.
Perhaps this could be alleviated:
C:/installs/Ruby192/lib/ruby/gems/1.9.1/gems/rspec-mocks-2.6.0.rc2/lib/rspec/mocks/any_instance.rb:19: warning: shadowing outer local variable - instance
I have fixed the issue with tests at albus522/rspec-mocks@ bdb3eb3
If you unstub a parent class and then a child class, the child class will be given methods from the parent. e.g.
irb> require 'rspec'
irb> RSpec::Mocks::setup(Object.new)
irb> class Foo; end
irb> class Bar < Foo; end
irb> Foo.stub(:new)
irb> Bar.stub(:new)
irb> Foo.unstub(:new)
irb> Bar.unstub(:new)
irb> Bar.new
=> #<Foo:0x101ec4cd8>
I was playing with the new any_instance
method and I noticed that it fails when using something like User.any_instance.stub :name => "John Doe"
.
The spec fails with this message:
Failure/Error: User.any_instance.stub :name => "John Doe"
TypeError:
{:name=>"John Doe"} is not a symbol
I have the following code which does not work. Version 2.6.0.
describe "foo" do
before do
Object.any_instance.stub(:foo).and_return(:return_value)
end
it "any_instance" do
o = Object.new
o.foo.should eq(:return_value)
end
end
before(:all) has the same outcome. I get:
Failures:
1) foo any_instance
Failure/Error: Object.any_instance.stub(:foo).and_return(:return_value)
NoMethodError:
undefined method `any_instance' for Object:Class
If I put the any_instance call inside of the it-block it is working as expected. Is it supposed to work? :-)
thing.stub_chain("this.that.the_other").and_return("this value")
Seems more intention revealing than:
thing.stub_chain(:this, :that, :the_other).and_return("this value")
I noticed that this spec from RSpec 1.3 hasn't been ported over to 2.0:
http://github.com/dchelimsky/rspec/blob/master/spec/spec/mocks/stub_chain_spec.rb#L33
Is there a reason for this? I would like to be able to create stub_chains shared messages at the beginning.
def create
@city = City.new(params[:city])
respond_with do |format|
if @city.save
format.html { redirect_to(admin_city_path(@city), :notice => 'City was successfully created.') }
else
format.html { render :action => "new" }
end
end
end
def mock_city(stubs={})
@mock_city ||= mock_model(City, stubs).as_null_object
end
describe "with valid params" do
it "assigns a newly created city as @city" do
City.stub(:new).with({'these' => 'params'}) { mock_city(:save => true) }
post :create, :city => {'these' => 'params'}
assigns(:city).should be(mock_city)
end
it "redirects to the created city" do
City.stub(:new) { mock_city(:save => true) }
post :create, :city => {}
response.should redirect_to(city_url(mock_city))
end
end
The problem seems to be with:
admin_city_path(@city)
Resulting in this error msg:
TypeError: RSpec::Mocks::Mock#to_hash should return Hash
Rspec has trouble stubbing methods whose classes redefine public
. Presumably similar problems arise with other visibility modifying methods. Unfortunately, this makes testing, e.g. Sinatra apps, difficult.
# test.rb
#!/usr/bin/env ruby
require 'rubygems'
require 'rspec'
class MyClass
def self.public; nil; end
def foo; bar; end
def bar; "bar"; end
end
describe MyClass do
it "should do the right thing" do
instance = MyClass.new
instance.should_receive :bar
instance.foo
end
end
Rspec fails when attempting to stub :bar
$ rspec --version
2.5.1
$ rspec test.rb
F
Failures:
1) MyClass should do the right thing
Failure/Error: def self.public; nil; end
ArgumentError:
wrong number of arguments (1 for 0)
# ./test.rb:7:in `public'
# ./test.rb:16:in `block (2 levels) in <top (required)>'
Finished in 0.00058 seconds
1 example, 1 failure
rspec should stub the method. The above test should pass.
(Moved from https://github.com/rspec/rspec-expectations/issues#issue/42)
specify do
@mymock = mock(:test)
@mymock.should_receive(:test).with(1,2,3).once
@mymock.should_receive(:test).with(3,2,1).once
@mymock.test(1,2,3)
@mymock.test(3,2,2)
end
outputs:
Failures:
1) TestTest test test
Failure/Error: @mymock.test(3,2,2)
Mock :test received :test with unexpected arguments
expected: (1, 2, 3)
got: (3, 2, 2)
Shouldn't it report:
expected: (3,2,1)
got: (3,2,2)
My cleanup branch has a couple commits you may want:
I encountered a weird issue with 2.6.0.rc2 where I was stubbing a method on any_instance of a model. In the model specs (which were run after the controller specs) my tests were showing that the method was undefined.
from builds_controller_spec.rb:
before do
Build.any_instance.stub(:already_built?).and_return(false)
end
it "should not create any builds when both builds already exist" do
Build.any_instance.stub(:already_built?).and_return(true)
post :create, :build => { :slot => 'something' }
Build.count.should == 0
end
from build_spec.rb:
it { should respond_to :already_built? }
If I run the controller spec first, I see this:
Failure/Error: it { should respond_to :already_built? }
expected #<Build id: nil ...> to respond to :already_built?
If I run the tests in the opposite order, everything is fine. I've narrowed the cause down to the specific any_instance line in the controller spec because if I comment out that one line, all of the other tests pass.
My assumption is that because I'm stubbing the same method on any_instance twice, it actually deletes the real method when cleaning up the 2nd time after the spec block.
Background: http://github.com/rspec/rspec-rails/issues#issue/114
require 'rspec-mocks'
should not do any of:
should_receive
to Object
should_not_receive
to Object
stub
to Object
double
, mock
, or stub
methods to ExampleGroup
or any the test-case class of other consuming frameworkBecause some classes can override send method (for example TextMagic::API uses send method to send the sms through gateway, which makes it impossible to mock).
I will submit pull request soon.
Very likely that rspec-mocks just needs to implement to_str
This fails:
obj = double('obj').as_null_object obj.should respond_to(:any_message_it_gets)
And be sure to notify Aslak when this is done.
I'm specing some behavior that depends on the existence or absence of a file. I'm doing so with a stub:
context 'when the file exists' do before(:each) { File.stub(:exist?).with(file_name).and_return(true) } it "returns :bar from #foo" do described_class.new(file_name).foo.should == :bar end end
This works fine except that described_class's initializer also calls File.exist? with a different argument. That causes an error: NoMethodError: undefined method 'exist?' for IO:Class
.
It seems to me that an argument-limited stub of an existing method should delegate to the original method definition when the method is called with a different argument, rather than raising a NoMethodError. My stubbing of File.exist? for file x should not effect File.exist?(y).
Hi If i have two tests like this:
it "should call the method" do
SomeClass.any_instance.expects(:the_method)
@my_test_object.a_method_that_calls_the_method
end
it "should reset the authenticator application data" do
@my_test_object.a_method_that_calls_the_method
@my_test_object.some_property.should == "something else"
end
So in short: two test-blocks, where in the first i check if the method is actually called, and in the second i check for the effects of the complete method --including the previously stubbed method.
What happens then: in the second test the actual method is not called, by I get the error that the expectation was received again. So somehow, the any_instance
sticks between tests, and I would expect it to last for only the current scope (test/context/ ...).
Is this the intended behaviour?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.