tracks/vendor/plugins/rspec/spec/spec/mocks/mock_spec.rb
Luke Melia 35ae5fc431 Next step in upgrading Tracks to Rails 2.2. Some highlights:
* Ran rake rails:update
* Added old actionwebservice framework
* Updated RSpec and RSpec-Rails
* Removed asset_packager plugin (not compatible, Scott no longer maintaining), and replaced with bundle_fu. See the bundle_fu README for more info.
* Hacks to UJS and ARTS plugins, which are no longer supported. Probably should move off both UJS and RJS.
* Hack to flashobject_helper plugin (upgrade to Rails 2.2-compatible version if/when it comes out.)
* Hack to skinny-spec plugin, for Rails 2.2 compatibility. Should check for official release.
* Hacks to resource_feeder plugin, for Rails 2.2 compatibility. Should check for official release (not likely) or move off it.
* Addressed some deprecation warnings. More to come.
* My mobile mime type hackery is no longer necessary with new Rails features. Yay!
* Updated environment.rb.tmpl with changes

TODO:
* Restore view specs marked pending
* Fix failing integration tests.
* Try selenium tests.
* Investigate OpenID support.
* Address deprecation warnings.
* Consider moving parts of environment.rb to initializers
* Address annoying config.gem warning about highline gem
2008-11-30 00:34:15 -05:00

555 lines
20 KiB
Ruby

require File.dirname(__FILE__) + '/../../spec_helper'
module Spec
module Mocks
describe Mock do
before(:each) do
@mock = mock("test mock")
end
after(:each) do
@mock.rspec_reset
end
it "should report line number of expectation of unreceived message" do
expected_error_line = __LINE__; @mock.should_receive(:wont_happen).with("x", 3)
begin
@mock.rspec_verify
violated
rescue MockExpectationError => e
# NOTE - this regexp ended w/ $, but jruby adds extra info at the end of the line
e.backtrace[0].should match(/#{File.basename(__FILE__)}:#{expected_error_line}/)
end
end
it "should report line number of expectation of unreceived message after #should_receive after similar stub" do
@mock.stub!(:wont_happen)
expected_error_line = __LINE__; @mock.should_receive(:wont_happen).with("x", 3)
begin
@mock.rspec_verify
violated
rescue MockExpectationError => e
# NOTE - this regexp ended w/ $, but jruby adds extra info at the end of the line
e.backtrace[0].should match(/#{File.basename(__FILE__)}:#{expected_error_line}/)
end
end
it "should pass when not receiving message specified as not to be received" do
@mock.should_not_receive(:not_expected)
@mock.rspec_verify
end
it "should pass when receiving message specified as not to be received with different args" do
@mock.should_not_receive(:message).with("unwanted text")
@mock.should_receive(:message).with("other text")
@mock.message "other text"
@mock.rspec_verify
end
it "should fail when receiving message specified as not to be received" do
@mock.should_not_receive(:not_expected)
lambda {
@mock.not_expected
violated
}.should raise_error(MockExpectationError, "Mock 'test mock' expected :not_expected with (no args) 0 times, but received it once")
end
it "should fail when receiving message specified as not to be received with args" do
@mock.should_not_receive(:not_expected).with("unexpected text")
lambda {
@mock.not_expected("unexpected text")
violated
}.should raise_error(MockExpectationError, "Mock 'test mock' expected :not_expected with (\"unexpected text\") 0 times, but received it once")
end
it "should pass when receiving message specified as not to be received with wrong args" do
@mock.should_not_receive(:not_expected).with("unexpected text")
@mock.not_expected "really unexpected text"
@mock.rspec_verify
end
it "should allow block to calculate return values" do
@mock.should_receive(:something).with("a","b","c").and_return { |a,b,c| c+b+a }
@mock.something("a","b","c").should == "cba"
@mock.rspec_verify
end
it "should allow parameter as return value" do
@mock.should_receive(:something).with("a","b","c").and_return("booh")
@mock.something("a","b","c").should == "booh"
@mock.rspec_verify
end
it "should return nil if no return value set" do
@mock.should_receive(:something).with("a","b","c")
@mock.something("a","b","c").should be_nil
@mock.rspec_verify
end
it "should raise exception if args don't match when method called" do
@mock.should_receive(:something).with("a","b","c").and_return("booh")
lambda {
@mock.something("a","d","c")
violated
}.should raise_error(MockExpectationError, "Mock 'test mock' expected :something with (\"a\", \"b\", \"c\") but received it with (\"a\", \"d\", \"c\")")
end
it "should raise exception if args don't match when method called even when the method is stubbed" do
@mock.stub!(:something)
@mock.should_receive(:something).with("a","b","c")
lambda {
@mock.something("a","d","c")
@mock.rspec_verify
}.should raise_error(MockExpectationError, "Mock 'test mock' expected :something with (\"a\", \"b\", \"c\") but received it with (\"a\", \"d\", \"c\")")
end
it "should raise exception if args don't match when method called even when using null_object" do
@mock = mock("test mock", :null_object => true)
@mock.should_receive(:something).with("a","b","c")
lambda {
@mock.something("a","d","c")
@mock.rspec_verify
}.should raise_error(MockExpectationError, "Mock 'test mock' expected :something with (\"a\", \"b\", \"c\") but received it with (\"a\", \"d\", \"c\")")
end
it "should fail if unexpected method called" do
lambda {
@mock.something("a","b","c")
violated
}.should raise_error(MockExpectationError, "Mock 'test mock' received unexpected message :something with (\"a\", \"b\", \"c\")")
end
it "should use block for expectation if provided" do
@mock.should_receive(:something) do | a, b |
a.should == "a"
b.should == "b"
"booh"
end
@mock.something("a", "b").should == "booh"
@mock.rspec_verify
end
it "should fail if expectation block fails" do
@mock.should_receive(:something) {| bool | bool.should be_true}
lambda {
@mock.something false
}.should raise_error(MockExpectationError, /Mock 'test mock' received :something but passed block failed with: expected true, got false/)
end
it "should fail right away when method defined as never is received" do
@mock.should_receive(:not_expected).never
lambda {
@mock.not_expected
}.should raise_error(MockExpectationError, "Mock 'test mock' expected :not_expected with (no args) 0 times, but received it once")
end
it "should eventually fail when method defined as never is received" do
@mock.should_receive(:not_expected).never
lambda {
@mock.not_expected
}.should raise_error(MockExpectationError, "Mock 'test mock' expected :not_expected with (no args) 0 times, but received it once")
end
it "should raise when told to" do
@mock.should_receive(:something).and_raise(RuntimeError)
lambda do
@mock.something
end.should raise_error(RuntimeError)
end
it "should raise passed an Exception instance" do
error = RuntimeError.new("error message")
@mock.should_receive(:something).and_raise(error)
lambda {
@mock.something
}.should raise_error(RuntimeError, "error message")
end
it "should raise RuntimeError with passed message" do
@mock.should_receive(:something).and_raise("error message")
lambda {
@mock.something
}.should raise_error(RuntimeError, "error message")
end
it "should not raise when told to if args dont match" do
@mock.should_receive(:something).with(2).and_raise(RuntimeError)
lambda {
@mock.something 1
}.should raise_error(MockExpectationError)
end
it "should throw when told to" do
@mock.should_receive(:something).and_throw(:blech)
lambda {
@mock.something
}.should throw_symbol(:blech)
end
it "should raise when explicit return and block constrained" do
lambda {
@mock.should_receive(:fruit) do |colour|
:strawberry
end.and_return :apple
}.should raise_error(AmbiguousReturnError)
end
it "should ignore args on any args" do
@mock.should_receive(:something).at_least(:once).with(any_args)
@mock.something
@mock.something 1
@mock.something "a", 2
@mock.something [], {}, "joe", 7
@mock.rspec_verify
end
it "should fail on no args if any args received" do
@mock.should_receive(:something).with(no_args())
lambda {
@mock.something 1
}.should raise_error(MockExpectationError, "Mock 'test mock' expected :something with (no args) but received it with (1)")
end
it "should fail when args are expected but none are received" do
@mock.should_receive(:something).with(1)
lambda {
@mock.something
}.should raise_error(MockExpectationError, "Mock 'test mock' expected :something with (1) but received it with (no args)")
end
it "should return value from block by default" do
@mock.stub!(:method_that_yields).and_yield
@mock.method_that_yields { :returned_obj }.should == :returned_obj
@mock.rspec_verify
end
it "should yield 0 args to blocks that take a variable number of arguments" do
@mock.should_receive(:yield_back).with(no_args()).once.and_yield
a = nil
@mock.yield_back {|*a|}
a.should == []
@mock.rspec_verify
end
it "should yield 0 args multiple times to blocks that take a variable number of arguments" do
@mock.should_receive(:yield_back).once.with(no_args()).once.and_yield.
and_yield
a = nil
b = []
@mock.yield_back {|*a| b << a}
b.should == [ [], [] ]
@mock.rspec_verify
end
it "should yield one arg to blocks that take a variable number of arguments" do
@mock.should_receive(:yield_back).with(no_args()).once.and_yield(99)
a = nil
@mock.yield_back {|*a|}
a.should == [99]
@mock.rspec_verify
end
it "should yield one arg 3 times consecutively to blocks that take a variable number of arguments" do
@mock.should_receive(:yield_back).once.with(no_args()).once.and_yield(99).
and_yield(43).
and_yield("something fruity")
a = nil
b = []
@mock.yield_back {|*a| b << a}
b.should == [[99], [43], ["something fruity"]]
@mock.rspec_verify
end
it "should yield many args to blocks that take a variable number of arguments" do
@mock.should_receive(:yield_back).with(no_args()).once.and_yield(99, 27, "go")
a = nil
@mock.yield_back {|*a|}
a.should == [99, 27, "go"]
@mock.rspec_verify
end
it "should yield many args 3 times consecutively to blocks that take a variable number of arguments" do
@mock.should_receive(:yield_back).once.with(no_args()).once.and_yield(99, :green, "go").
and_yield("wait", :amber).
and_yield("stop", 12, :red)
a = nil
b = []
@mock.yield_back {|*a| b << a}
b.should == [[99, :green, "go"], ["wait", :amber], ["stop", 12, :red]]
@mock.rspec_verify
end
it "should yield single value" do
@mock.should_receive(:yield_back).with(no_args()).once.and_yield(99)
a = nil
@mock.yield_back {|a|}
a.should == 99
@mock.rspec_verify
end
it "should yield single value 3 times consecutively" do
@mock.should_receive(:yield_back).once.with(no_args()).once.and_yield(99).
and_yield(43).
and_yield("something fruity")
a = nil
b = []
@mock.yield_back {|a| b << a}
b.should == [99, 43, "something fruity"]
@mock.rspec_verify
end
it "should yield two values" do
@mock.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
a, b = nil
@mock.yield_back {|a,b|}
a.should == 'wha'
b.should == 'zup'
@mock.rspec_verify
end
it "should yield two values 3 times consecutively" do
@mock.should_receive(:yield_back).once.with(no_args()).once.and_yield('wha', 'zup').
and_yield('not', 'down').
and_yield(14, 65)
a, b = nil
c = []
@mock.yield_back {|a,b| c << [a, b]}
c.should == [['wha', 'zup'], ['not', 'down'], [14, 65]]
@mock.rspec_verify
end
it "should fail when calling yielding method with wrong arity" do
@mock.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
lambda {
@mock.yield_back {|a|}
}.should raise_error(MockExpectationError, "Mock 'test mock' yielded |\"wha\", \"zup\"| to block with arity of 1")
end
it "should fail when calling yielding method consecutively with wrong arity" do
@mock.should_receive(:yield_back).once.with(no_args()).once.and_yield('wha', 'zup').
and_yield('down').
and_yield(14, 65)
lambda {
a, b = nil
c = []
@mock.yield_back {|a,b| c << [a, b]}
}.should raise_error(MockExpectationError, "Mock 'test mock' yielded |\"down\"| to block with arity of 2")
end
it "should fail when calling yielding method without block" do
@mock.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
lambda {
@mock.yield_back
}.should raise_error(MockExpectationError, "Mock 'test mock' asked to yield |[\"wha\", \"zup\"]| but no block was passed")
end
it "should be able to mock send" do
@mock.should_receive(:send).with(any_args)
@mock.send 'hi'
@mock.rspec_verify
end
it "should be able to raise from method calling yielding mock" do
@mock.should_receive(:yield_me).and_yield 44
lambda {
@mock.yield_me do |x|
raise "Bang"
end
}.should raise_error(StandardError, "Bang")
@mock.rspec_verify
end
it "should clear expectations after verify" do
@mock.should_receive(:foobar)
@mock.foobar
@mock.rspec_verify
lambda {
@mock.foobar
}.should raise_error(MockExpectationError, "Mock 'test mock' received unexpected message :foobar with (no args)")
end
it "should restore objects to their original state on rspec_reset" do
mock = mock("this is a mock")
mock.should_receive(:blah)
mock.rspec_reset
mock.rspec_verify #should throw if reset didn't work
end
it "should work even after method_missing starts raising NameErrors instead of NoMethodErrors" do
# Object#method_missing throws either NameErrors or NoMethodErrors.
#
# On a fresh ruby program Object#method_missing:
# * raises a NoMethodError when called directly
# * raises a NameError when called indirectly
#
# Once Object#method_missing has been called at least once (on any object)
# it starts behaving differently:
# * raises a NameError when called directly
# * raises a NameError when called indirectly
#
# There was a bug in Mock#method_missing that relied on the fact
# that calling Object#method_missing directly raises a NoMethodError.
# This example tests that the bug doesn't exist anymore.
# Ensures that method_missing always raises NameErrors.
a_method_that_doesnt_exist rescue
@mock.should_receive(:foobar)
@mock.foobar
@mock.rspec_verify
lambda { @mock.foobar }.should_not raise_error(NameError)
lambda { @mock.foobar }.should raise_error(MockExpectationError)
end
it "should temporarily replace a method stub on a mock" do
@mock.stub!(:msg).and_return(:stub_value)
@mock.should_receive(:msg).with(:arg).and_return(:mock_value)
@mock.msg(:arg).should equal(:mock_value)
@mock.msg.should equal(:stub_value)
@mock.msg.should equal(:stub_value)
@mock.rspec_verify
end
it "should not require a different signature to replace a method stub" do
@mock.stub!(:msg).and_return(:stub_value)
@mock.should_receive(:msg).and_return(:mock_value)
@mock.msg(:arg).should equal(:mock_value)
@mock.msg.should equal(:stub_value)
@mock.msg.should equal(:stub_value)
@mock.rspec_verify
end
it "should raise an error when a previously stubbed method has a negative expectation" do
@mock.stub!(:msg).and_return(:stub_value)
@mock.should_not_receive(:msg).and_return(:mock_value)
lambda {@mock.msg(:arg)}.should raise_error(MockExpectationError)
end
it "should temporarily replace a method stub on a non-mock" do
non_mock = Object.new
non_mock.stub!(:msg).and_return(:stub_value)
non_mock.should_receive(:msg).with(:arg).and_return(:mock_value)
non_mock.msg(:arg).should equal(:mock_value)
non_mock.msg.should equal(:stub_value)
non_mock.msg.should equal(:stub_value)
non_mock.rspec_verify
end
it "should return the stubbed value when no new value specified" do
@mock.stub!(:msg).and_return(:stub_value)
@mock.should_receive(:msg)
@mock.msg.should equal(:stub_value)
@mock.rspec_verify
end
it "should not mess with the stub's yielded values when also mocked" do
@mock.stub!(:yield_back).and_yield(:stub_value)
@mock.should_receive(:yield_back).and_yield(:mock_value)
@mock.yield_back{|v| v.should == :mock_value }
@mock.yield_back{|v| v.should == :stub_value }
@mock.rspec_verify
end
it "should yield multiple values after a similar stub" do
File.stub!(:open).and_yield(:stub_value)
File.should_receive(:open).and_yield(:first_call).and_yield(:second_call)
yielded_args = []
File.open {|v| yielded_args << v }
yielded_args.should == [:first_call, :second_call]
File.open {|v| v.should == :stub_value }
File.rspec_verify
end
it "should assign stub return values" do
mock = Mock.new('name', :message => :response)
mock.message.should == :response
end
end
describe "a mock message receiving a block" do
before(:each) do
@mock = mock("mock")
@calls = 0
end
def add_call
@calls = @calls + 1
end
it "should call the block after #should_receive" do
@mock.should_receive(:foo) { add_call }
@mock.foo
@calls.should == 1
end
it "should call the block after #should_receive after a similar stub" do
@mock.stub!(:foo).and_return(:bar)
@mock.should_receive(:foo) { add_call }
@mock.foo
@calls.should == 1
end
it "should call the block after #once" do
@mock.should_receive(:foo).once { add_call }
@mock.foo
@calls.should == 1
end
it "should call the block after #twice" do
@mock.should_receive(:foo).twice { add_call }
@mock.foo
@mock.foo
@calls.should == 2
end
it "should call the block after #times" do
@mock.should_receive(:foo).exactly(10).times { add_call }
(1..10).each { @mock.foo }
@calls.should == 10
end
it "should call the block after #any_number_of_times" do
@mock.should_receive(:foo).any_number_of_times { add_call }
(1..7).each { @mock.foo }
@calls.should == 7
end
it "should call the block after #ordered" do
@mock.should_receive(:foo).ordered { add_call }
@mock.should_receive(:bar).ordered { add_call }
@mock.foo
@mock.bar
@calls.should == 2
end
end
describe 'string representation generated by #to_s' do
it 'should not contain < because that might lead to invalid HTML in some situations' do
mock = mock("Dog")
valid_html_str = "#{mock}"
valid_html_str.should_not include('<')
end
end
end
end