rspec-mocks 2.10.1 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Changelog.md +26 -1
- data/README.md +14 -2
- data/features/stubbing_constants/README.md +62 -0
- data/features/stubbing_constants/stub_defined_constant.feature +79 -0
- data/features/stubbing_constants/stub_undefined_constant.feature +50 -0
- data/lib/rspec/mocks/any_instance.rb +37 -1
- data/lib/rspec/mocks/any_instance/chain.rb +0 -81
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +57 -0
- data/lib/rspec/mocks/any_instance/recorder.rb +6 -1
- data/lib/rspec/mocks/any_instance/stub_chain.rb +37 -0
- data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +25 -0
- data/lib/rspec/mocks/argument_list_matcher.rb +93 -0
- data/lib/rspec/mocks/argument_matchers.rb +39 -31
- data/lib/rspec/mocks/error_generator.rb +7 -0
- data/lib/rspec/mocks/example_methods.rb +41 -0
- data/lib/rspec/mocks/framework.rb +2 -1
- data/lib/rspec/mocks/message_expectation.rb +21 -13
- data/lib/rspec/mocks/methods.rb +4 -0
- data/lib/rspec/mocks/proxy.rb +10 -4
- data/lib/rspec/mocks/stub_const.rb +280 -0
- data/lib/rspec/mocks/test_double.rb +3 -2
- data/lib/rspec/mocks/version.rb +1 -1
- data/spec/rspec/mocks/any_instance/message_chains_spec.rb +1 -1
- data/spec/rspec/mocks/any_instance_spec.rb +66 -26
- data/spec/rspec/mocks/argument_expectation_spec.rb +7 -7
- data/spec/rspec/mocks/at_least_spec.rb +14 -0
- data/spec/rspec/mocks/block_return_value_spec.rb +8 -0
- data/spec/rspec/mocks/mock_spec.rb +33 -20
- data/spec/rspec/mocks/multiple_return_value_spec.rb +2 -2
- data/spec/rspec/mocks/null_object_mock_spec.rb +22 -0
- data/spec/rspec/mocks/stub_chain_spec.rb +45 -45
- data/spec/rspec/mocks/stub_const_spec.rb +309 -0
- data/spec/rspec/mocks/stub_spec.rb +2 -2
- data/spec/spec_helper.rb +0 -40
- metadata +18 -6
- data/lib/rspec/mocks/argument_expectation.rb +0 -52
data/lib/rspec/mocks/methods.rb
CHANGED
data/lib/rspec/mocks/proxy.rb
CHANGED
@@ -65,6 +65,7 @@ module RSpec
|
|
65
65
|
|
66
66
|
# @private
|
67
67
|
def add_message_expectation(location, method_name, opts={}, &block)
|
68
|
+
block ||= Proc.new { @object } if null_object?
|
68
69
|
method_double[method_name].add_expectation @error_generator, @expectation_ordering, location, opts, &block
|
69
70
|
end
|
70
71
|
|
@@ -128,7 +129,7 @@ module RSpec
|
|
128
129
|
raise_unexpected_message_args_error(expectation, *args) unless (has_negative_expectation?(message) or null_object?)
|
129
130
|
elsif stub = find_almost_matching_stub(message, *args)
|
130
131
|
stub.advise(*args)
|
131
|
-
|
132
|
+
raise_missing_default_stub_error(stub, *args)
|
132
133
|
elsif @object.is_a?(Class)
|
133
134
|
@object.superclass.__send__(message, *args, &block)
|
134
135
|
else
|
@@ -136,14 +137,19 @@ module RSpec
|
|
136
137
|
end
|
137
138
|
end
|
138
139
|
|
140
|
+
# @private
|
141
|
+
def raise_unexpected_message_error(method_name, *args)
|
142
|
+
@error_generator.raise_unexpected_message_error method_name, *args
|
143
|
+
end
|
144
|
+
|
139
145
|
# @private
|
140
146
|
def raise_unexpected_message_args_error(expectation, *args)
|
141
147
|
@error_generator.raise_unexpected_message_args_error(expectation, *args)
|
142
148
|
end
|
143
149
|
|
144
150
|
# @private
|
145
|
-
def
|
146
|
-
@error_generator.
|
151
|
+
def raise_missing_default_stub_error(expectation, *args)
|
152
|
+
@error_generator.raise_missing_default_stub_error(expectation, *args)
|
147
153
|
end
|
148
154
|
|
149
155
|
private
|
@@ -157,7 +163,7 @@ module RSpec
|
|
157
163
|
end
|
158
164
|
|
159
165
|
def find_matching_expectation(method_name, *args)
|
160
|
-
method_double[method_name].expectations.find {|expectation| expectation.matches?(method_name, *args) && !expectation.called_max_times?} ||
|
166
|
+
(method_double[method_name].expectations.find {|expectation| expectation.matches?(method_name, *args) && !expectation.called_max_times?}) ||
|
161
167
|
method_double[method_name].expectations.find {|expectation| expectation.matches?(method_name, *args)}
|
162
168
|
end
|
163
169
|
|
@@ -0,0 +1,280 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Mocks
|
3
|
+
# Provides recursive constant lookup methods useful for
|
4
|
+
# constant stubbing.
|
5
|
+
# @api private
|
6
|
+
module RecursiveConstMethods
|
7
|
+
def recursive_const_get(name)
|
8
|
+
name.split('::').inject(Object) { |mod, name| mod.const_get name }
|
9
|
+
end
|
10
|
+
|
11
|
+
def recursive_const_defined?(name)
|
12
|
+
name.split('::').inject([Object, '']) do |(mod, full_name), name|
|
13
|
+
yield(full_name, name) if block_given? && !mod.is_a?(Module)
|
14
|
+
return false unless mod.const_defined?(name)
|
15
|
+
[mod.const_get(name), [mod, name].join('::')]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Provides information about constants that may (or may not)
|
21
|
+
# have been stubbed by rspec-mocks.
|
22
|
+
class Constant
|
23
|
+
extend RecursiveConstMethods
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
def initialize(name)
|
27
|
+
@name = name
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [String] The fully qualified name of the constant.
|
31
|
+
attr_reader :name
|
32
|
+
|
33
|
+
# @return [Object, nil] The original value (e.g. before it
|
34
|
+
# was stubbed by rspec-mocks) of the constant, or
|
35
|
+
# nil if the constant was not previously defined.
|
36
|
+
attr_accessor :original_value
|
37
|
+
|
38
|
+
# @api private
|
39
|
+
attr_writer :previously_defined, :stubbed
|
40
|
+
|
41
|
+
# @return [Boolean] Whether or not the constant was defined
|
42
|
+
# before the current example.
|
43
|
+
def previously_defined?
|
44
|
+
@previously_defined
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Boolean] Whether or not rspec-mocks has stubbed
|
48
|
+
# this constant.
|
49
|
+
def stubbed?
|
50
|
+
@stubbed
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
"#<#{self.class.name} #{name}>"
|
55
|
+
end
|
56
|
+
alias inspect to_s
|
57
|
+
|
58
|
+
# @api private
|
59
|
+
def self.unstubbed(name)
|
60
|
+
const = new(name)
|
61
|
+
const.previously_defined = recursive_const_defined?(name)
|
62
|
+
const.stubbed = false
|
63
|
+
const.original_value = recursive_const_get(name) if const.previously_defined?
|
64
|
+
|
65
|
+
const
|
66
|
+
end
|
67
|
+
private_class_method :unstubbed
|
68
|
+
|
69
|
+
# Queries rspec-mocks to find out information about the named constant.
|
70
|
+
#
|
71
|
+
# @param [String] name the name of the constant
|
72
|
+
# @return [Constant] an object contaning information about the named
|
73
|
+
# constant.
|
74
|
+
def self.original(name)
|
75
|
+
stubber = ConstantStubber.find(name)
|
76
|
+
stubber ? stubber.to_constant : unstubbed(name)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Provides a means to stub constants.
|
81
|
+
class ConstantStubber
|
82
|
+
extend RecursiveConstMethods
|
83
|
+
|
84
|
+
# Stubs a constant.
|
85
|
+
#
|
86
|
+
# @param (see ExampleMethods#stub_const)
|
87
|
+
# @option (see ExampleMethods#stub_const)
|
88
|
+
# @return (see ExampleMethods#stub_const)
|
89
|
+
#
|
90
|
+
# @see ExampleMethods#stub_const
|
91
|
+
# @note It's recommended that you use `stub_const` in your
|
92
|
+
# examples. This is an alternate public API that is provided
|
93
|
+
# so you can stub constants in other contexts (e.g. helper
|
94
|
+
# classes).
|
95
|
+
def self.stub(constant_name, value, options = {})
|
96
|
+
stubber = if recursive_const_defined?(constant_name, &raise_on_invalid_const)
|
97
|
+
DefinedConstantReplacer
|
98
|
+
else
|
99
|
+
UndefinedConstantSetter
|
100
|
+
end
|
101
|
+
|
102
|
+
stubber = stubber.new(constant_name, value, options[:transfer_nested_constants])
|
103
|
+
stubbers << stubber
|
104
|
+
|
105
|
+
stubber.stub
|
106
|
+
ensure_registered_with_mocks_space
|
107
|
+
value
|
108
|
+
end
|
109
|
+
|
110
|
+
# Contains common functionality used by both of the constant stubbers.
|
111
|
+
#
|
112
|
+
# @api private
|
113
|
+
class BaseStubber
|
114
|
+
include RecursiveConstMethods
|
115
|
+
|
116
|
+
attr_reader :original_value, :full_constant_name
|
117
|
+
|
118
|
+
def initialize(full_constant_name, stubbed_value, transfer_nested_constants)
|
119
|
+
@full_constant_name = full_constant_name
|
120
|
+
@stubbed_value = stubbed_value
|
121
|
+
@transfer_nested_constants = transfer_nested_constants
|
122
|
+
@context_parts = @full_constant_name.split('::')
|
123
|
+
@const_name = @context_parts.pop
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_constant
|
127
|
+
const = Constant.new(full_constant_name)
|
128
|
+
const.stubbed = true
|
129
|
+
const.previously_defined = previously_defined?
|
130
|
+
const.original_value = original_value
|
131
|
+
|
132
|
+
const
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Replaces a defined constant for the duration of an example.
|
137
|
+
#
|
138
|
+
# @api private
|
139
|
+
class DefinedConstantReplacer < BaseStubber
|
140
|
+
def stub
|
141
|
+
@context = recursive_const_get(@context_parts.join('::'))
|
142
|
+
@original_value = @context.const_get(@const_name)
|
143
|
+
|
144
|
+
constants_to_transfer = verify_constants_to_transfer!
|
145
|
+
|
146
|
+
@context.send(:remove_const, @const_name)
|
147
|
+
@context.const_set(@const_name, @stubbed_value)
|
148
|
+
|
149
|
+
transfer_nested_constants(constants_to_transfer)
|
150
|
+
end
|
151
|
+
|
152
|
+
def previously_defined?
|
153
|
+
true
|
154
|
+
end
|
155
|
+
|
156
|
+
def rspec_reset
|
157
|
+
@context.send(:remove_const, @const_name)
|
158
|
+
@context.const_set(@const_name, @original_value)
|
159
|
+
end
|
160
|
+
|
161
|
+
def transfer_nested_constants(constants)
|
162
|
+
constants.each do |const|
|
163
|
+
@stubbed_value.const_set(const, original_value.const_get(const))
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def verify_constants_to_transfer!
|
168
|
+
return [] unless @transfer_nested_constants
|
169
|
+
|
170
|
+
{ @original_value => "the original value", @stubbed_value => "the stubbed value" }.each do |value, description|
|
171
|
+
unless value.respond_to?(:constants)
|
172
|
+
raise ArgumentError,
|
173
|
+
"Cannot transfer nested constants for #{@full_constant_name} " +
|
174
|
+
"since #{description} is not a class or module and only classes " +
|
175
|
+
"and modules support nested constants."
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
if @transfer_nested_constants.is_a?(Array)
|
180
|
+
@transfer_nested_constants = @transfer_nested_constants.map(&:to_s) if RUBY_VERSION == '1.8.7'
|
181
|
+
undefined_constants = @transfer_nested_constants - @original_value.constants
|
182
|
+
|
183
|
+
if undefined_constants.any?
|
184
|
+
available_constants = @original_value.constants - @transfer_nested_constants
|
185
|
+
raise ArgumentError,
|
186
|
+
"Cannot transfer nested constant(s) #{undefined_constants.join(' and ')} " +
|
187
|
+
"for #{@full_constant_name} since they are not defined. Did you mean " +
|
188
|
+
"#{available_constants.join(' or ')}?"
|
189
|
+
end
|
190
|
+
|
191
|
+
@transfer_nested_constants
|
192
|
+
else
|
193
|
+
@original_value.constants
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Sets an undefined constant for the duration of an example.
|
199
|
+
#
|
200
|
+
# @api private
|
201
|
+
class UndefinedConstantSetter < BaseStubber
|
202
|
+
def stub
|
203
|
+
remaining_parts = @context_parts.dup
|
204
|
+
@deepest_defined_const = @context_parts.inject(Object) do |klass, name|
|
205
|
+
break klass unless klass.const_defined?(name)
|
206
|
+
remaining_parts.shift
|
207
|
+
klass.const_get(name)
|
208
|
+
end
|
209
|
+
|
210
|
+
context = remaining_parts.inject(@deepest_defined_const) do |klass, name|
|
211
|
+
klass.const_set(name, Module.new)
|
212
|
+
end
|
213
|
+
|
214
|
+
@const_to_remove = remaining_parts.first || @const_name
|
215
|
+
context.const_set(@const_name, @stubbed_value)
|
216
|
+
end
|
217
|
+
|
218
|
+
def previously_defined?
|
219
|
+
false
|
220
|
+
end
|
221
|
+
|
222
|
+
def rspec_reset
|
223
|
+
@deepest_defined_const.send(:remove_const, @const_to_remove)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# Ensures the constant stubbing is registered with
|
228
|
+
# rspec-mocks space so that stubbed constants can
|
229
|
+
# be restored when examples finish.
|
230
|
+
#
|
231
|
+
# @api private
|
232
|
+
def self.ensure_registered_with_mocks_space
|
233
|
+
return if @registered_with_mocks_space
|
234
|
+
::RSpec::Mocks.space.add(self)
|
235
|
+
@registered_with_mocks_space = true
|
236
|
+
end
|
237
|
+
|
238
|
+
# Resets all stubbed constants. This is called automatically
|
239
|
+
# by rspec-mocks when an example finishes.
|
240
|
+
#
|
241
|
+
# @api private
|
242
|
+
def self.rspec_reset
|
243
|
+
@registered_with_mocks_space = false
|
244
|
+
|
245
|
+
# We use reverse order so that if the same constant
|
246
|
+
# was stubbed multiple times, the original value gets
|
247
|
+
# properly restored.
|
248
|
+
stubbers.reverse.each { |s| s.rspec_reset }
|
249
|
+
|
250
|
+
stubbers.clear
|
251
|
+
end
|
252
|
+
|
253
|
+
# The list of constant stubbers that have been used for
|
254
|
+
# the current example.
|
255
|
+
#
|
256
|
+
# @api private
|
257
|
+
def self.stubbers
|
258
|
+
@stubbers ||= []
|
259
|
+
end
|
260
|
+
|
261
|
+
def self.find(name)
|
262
|
+
stubbers.find { |s| s.full_constant_name == name }
|
263
|
+
end
|
264
|
+
|
265
|
+
# Used internally by the constant stubbing to raise a helpful
|
266
|
+
# error when a constant like "A::B::C" is stubbed and A::B is
|
267
|
+
# not a module (and thus, it's impossible to define "A::B::C"
|
268
|
+
# since only modules can have nested constants).
|
269
|
+
#
|
270
|
+
# @api private
|
271
|
+
def self.raise_on_invalid_const
|
272
|
+
lambda do |const_name, failed_name|
|
273
|
+
raise "Cannot stub constant #{failed_name} on #{const_name} " +
|
274
|
+
"since #{const_name} is not a module."
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
@@ -64,8 +64,10 @@ module RSpec
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def method_missing(message, *args, &block)
|
67
|
-
|
67
|
+
raise NoMethodError if message == :to_ary
|
68
|
+
return 0 if message == :to_int && __mock_proxy.null_object?
|
68
69
|
__mock_proxy.record_message_received(message, *args, &block)
|
70
|
+
|
69
71
|
begin
|
70
72
|
__mock_proxy.null_object? ? self : super
|
71
73
|
rescue NameError
|
@@ -99,4 +101,3 @@ module RSpec
|
|
99
101
|
end
|
100
102
|
end
|
101
103
|
end
|
102
|
-
|
data/lib/rspec/mocks/version.rb
CHANGED
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe RSpec::Mocks::AnyInstance::MessageChains do
|
4
4
|
let(:chains) { RSpec::Mocks::AnyInstance::MessageChains.new }
|
5
5
|
let(:stub_chain) { RSpec::Mocks::AnyInstance::StubChain.new }
|
6
|
-
let(:expectation_chain) { RSpec::Mocks::AnyInstance::
|
6
|
+
let(:expectation_chain) { RSpec::Mocks::AnyInstance::PositiveExpectationChain.new }
|
7
7
|
|
8
8
|
it "knows if a method does not have an expectation set on it" do
|
9
9
|
chains.add(:method_name, stub_chain)
|
@@ -34,13 +34,13 @@ module RSpec
|
|
34
34
|
lambda{ klass.any_instance.stub(:foo).and_yield(1).with("1") }.should raise_error(NoMethodError)
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
context "#stub_chain" do
|
39
39
|
it "raises an error if 'stub_chain' follows 'any_instance'" do
|
40
40
|
lambda{ klass.any_instance.and_return("1").stub_chain(:foo, :bar) }.should raise_error(NoMethodError)
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
context "#should_receive" do
|
45
45
|
it "raises an error if 'should_receive' follows 'with'" do
|
46
46
|
lambda{ klass.any_instance.with("1").should_receive(:foo) }.should raise_error(NoMethodError)
|
@@ -57,13 +57,13 @@ module RSpec
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
context "with #stub" do
|
62
62
|
it "does not suppress an exception when a method that doesn't exist is invoked" do
|
63
63
|
klass.any_instance.stub(:foo)
|
64
64
|
lambda{ klass.new.bar }.should raise_error(NoMethodError)
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
context 'multiple methods' do
|
68
68
|
it "allows multiple methods to be stubbed in a single invocation" do
|
69
69
|
klass.any_instance.stub(:foo => 'foo', :bar => 'bar')
|
@@ -71,12 +71,12 @@ module RSpec
|
|
71
71
|
instance.foo.should eq('foo')
|
72
72
|
instance.bar.should eq('bar')
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
it "adheres to the contract of multiple method stubbing withou any instance" do
|
76
76
|
Object.new.stub(:foo => 'foo', :bar => 'bar').should eq(:foo => 'foo', :bar => 'bar')
|
77
77
|
klass.any_instance.stub(:foo => 'foo', :bar => 'bar').should eq(:foo => 'foo', :bar => 'bar')
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
context "allows a chain of methods to be stubbed using #stub_chain" do
|
81
81
|
it "given symbols representing the methods" do
|
82
82
|
klass.any_instance.stub_chain(:one, :two, :three).and_return(:four)
|
@@ -87,14 +87,14 @@ module RSpec
|
|
87
87
|
klass.any_instance.stub_chain(:one, :two, :three => :four)
|
88
88
|
klass.new.one.two.three.should eq(:four)
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
it "given a string of '.' separated method names representing the chain" do
|
92
92
|
klass.any_instance.stub_chain('one.two.three').and_return(:four)
|
93
93
|
klass.new.one.two.three.should eq(:four)
|
94
94
|
end
|
95
95
|
end
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
98
|
context "behaves as 'every instance'" do
|
99
99
|
it "stubs every instance in the spec" do
|
100
100
|
klass.any_instance.stub(:foo).and_return(result = Object.new)
|
@@ -108,13 +108,13 @@ module RSpec
|
|
108
108
|
instance.foo.should eq(result)
|
109
109
|
end
|
110
110
|
end
|
111
|
-
|
111
|
+
|
112
112
|
context "with argument matching" do
|
113
|
-
before do
|
113
|
+
before do
|
114
114
|
klass.any_instance.stub(:foo).with(:param_one, :param_two).and_return(:result_one)
|
115
115
|
klass.any_instance.stub(:foo).with(:param_three, :param_four).and_return(:result_two)
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
118
|
it "returns the stubbed value when arguments match" do
|
119
119
|
instance = klass.new
|
120
120
|
instance.foo(:param_one, :param_two).should eq(:result_one)
|
@@ -127,11 +127,11 @@ module RSpec
|
|
127
127
|
end.to(raise_error(RSpec::Mocks::MockExpectationError))
|
128
128
|
end
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
context "with multiple stubs" do
|
132
|
-
before do
|
133
|
-
klass.any_instance.stub(:foo).and_return(1)
|
134
|
-
klass.any_instance.stub(:bar).and_return(2)
|
132
|
+
before do
|
133
|
+
klass.any_instance.stub(:foo).and_return(1)
|
134
|
+
klass.any_instance.stub(:bar).and_return(2)
|
135
135
|
end
|
136
136
|
|
137
137
|
it "stubs a method" do
|
@@ -196,7 +196,7 @@ module RSpec
|
|
196
196
|
klass.new.foo.should eq(klass.new.foo)
|
197
197
|
end
|
198
198
|
end
|
199
|
-
|
199
|
+
|
200
200
|
context "core ruby objects" do
|
201
201
|
it "works uniformly across *everything*" do
|
202
202
|
Object.any_instance.stub(:foo).and_return(1)
|
@@ -244,7 +244,7 @@ module RSpec
|
|
244
244
|
end.to raise_error(/Use stub instead/)
|
245
245
|
end
|
246
246
|
end
|
247
|
-
|
247
|
+
|
248
248
|
context "unstub implementation" do
|
249
249
|
it "replaces the stubbed method with the original method" do
|
250
250
|
klass.any_instance.stub(:existing_method)
|
@@ -264,7 +264,7 @@ module RSpec
|
|
264
264
|
klass.any_instance.stub(:existing_method_with_arguments).with(1)
|
265
265
|
klass.any_instance.stub(:existing_method_with_arguments).with(2)
|
266
266
|
klass.any_instance.unstub(:existing_method_with_arguments)
|
267
|
-
klass.new.existing_method_with_arguments(3).should eq
|
267
|
+
klass.new.existing_method_with_arguments(3).should eq(:three)
|
268
268
|
end
|
269
269
|
|
270
270
|
it "raises a MockExpectationError if the method has not been stubbed" do
|
@@ -273,6 +273,37 @@ module RSpec
|
|
273
273
|
end.should raise_error(RSpec::Mocks::MockExpectationError, 'The method `existing_method` was not stubbed or was already unstubbed')
|
274
274
|
end
|
275
275
|
end
|
276
|
+
|
277
|
+
context "with #should_not_receive" do
|
278
|
+
it "fails if the method is called" do
|
279
|
+
klass.any_instance.should_not_receive(:existing_method)
|
280
|
+
lambda { klass.new.existing_method }.should raise_error(RSpec::Mocks::MockExpectationError)
|
281
|
+
end
|
282
|
+
|
283
|
+
it "passes if no method is called" do
|
284
|
+
lambda { klass.any_instance.should_not_receive(:existing_method) }.should_not raise_error
|
285
|
+
end
|
286
|
+
|
287
|
+
it "passes if only a different method is called" do
|
288
|
+
klass.any_instance.should_not_receive(:existing_method)
|
289
|
+
lambda { klass.new.another_existing_method }.should_not raise_error
|
290
|
+
end
|
291
|
+
|
292
|
+
context "with constraints" do
|
293
|
+
it "fails if the method is called with the specified parameters" do
|
294
|
+
klass.any_instance.should_not_receive(:existing_method_with_arguments).with(:argument_one, :argument_two)
|
295
|
+
lambda do
|
296
|
+
klass.new.existing_method_with_arguments(:argument_one, :argument_two)
|
297
|
+
end.should raise_error(RSpec::Mocks::MockExpectationError)
|
298
|
+
end
|
299
|
+
|
300
|
+
it "passes if the method is called with different parameters" do
|
301
|
+
klass.any_instance.should_not_receive(:existing_method_with_arguments).with(:argument_one, :argument_two)
|
302
|
+
lambda { klass.new.existing_method_with_arguments(:argument_three, :argument_four) }.should_not raise_error
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
276
307
|
context "with #should_receive" do
|
277
308
|
let(:foo_expectation_error_message) { 'Exactly one instance should have received the following message(s) but didn\'t: foo' }
|
278
309
|
let(:existing_method_expectation_error_message) { 'Exactly one instance should have received the following message(s) but didn\'t: existing_method' }
|
@@ -406,11 +437,11 @@ module RSpec
|
|
406
437
|
end
|
407
438
|
|
408
439
|
context "with argument matching" do
|
409
|
-
before do
|
440
|
+
before do
|
410
441
|
klass.any_instance.should_receive(:foo).with(:param_one, :param_two).and_return(:result_one)
|
411
442
|
klass.any_instance.should_receive(:foo).with(:param_three, :param_four).and_return(:result_two)
|
412
443
|
end
|
413
|
-
|
444
|
+
|
414
445
|
it "returns the expected value when arguments match" do
|
415
446
|
instance = klass.new
|
416
447
|
instance.foo(:param_one, :param_two).should eq(:result_one)
|
@@ -434,7 +465,7 @@ module RSpec
|
|
434
465
|
instance.foo(:param_one, :param_two).should eq(:result_one)
|
435
466
|
instance.foo(:param_three, :param_four).should eq(:result_two)
|
436
467
|
end
|
437
|
-
|
468
|
+
|
438
469
|
it "fails when arguments do not match" do
|
439
470
|
instance = klass.new
|
440
471
|
expect do
|
@@ -676,21 +707,21 @@ module RSpec
|
|
676
707
|
klass.new.existing_method.should eq(existing_method_return_value)
|
677
708
|
end
|
678
709
|
end
|
679
|
-
|
710
|
+
|
680
711
|
context "private methods" do
|
681
712
|
before :each do
|
682
713
|
klass.any_instance.stub(:private_method).and_return(:something)
|
683
714
|
space.verify_all
|
684
715
|
end
|
685
|
-
|
716
|
+
|
686
717
|
it "cleans up the backed up method" do
|
687
718
|
klass.method_defined?(:__existing_method_without_any_instance__).should be_false
|
688
719
|
end
|
689
|
-
|
720
|
+
|
690
721
|
it "restores a stubbed private method after the spec is run" do
|
691
722
|
klass.private_method_defined?(:private_method).should be_true
|
692
723
|
end
|
693
|
-
|
724
|
+
|
694
725
|
it "ensures that the restored method behaves as it originally did" do
|
695
726
|
klass.new.send(:private_method).should eq(:private_method_return_value)
|
696
727
|
end
|
@@ -717,7 +748,7 @@ module RSpec
|
|
717
748
|
klass.new.send(:private_method).should eq(:private_method_return_value)
|
718
749
|
end
|
719
750
|
end
|
720
|
-
|
751
|
+
|
721
752
|
context "ensures that the subsequent specs do not see expectations set in previous specs" do
|
722
753
|
context "when the instance created after the expectation is set" do
|
723
754
|
it "first spec" do
|
@@ -780,6 +811,15 @@ module RSpec
|
|
780
811
|
end
|
781
812
|
end
|
782
813
|
|
814
|
+
context 'when used in conjunction with a `dup`' do
|
815
|
+
it "doesn't cause an infinite loop" do
|
816
|
+
Object.any_instance.stub(:some_method)
|
817
|
+
o = Object.new
|
818
|
+
o.some_method
|
819
|
+
lambda { o.dup.some_method }.should_not raise_error(SystemStackError)
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
783
823
|
end
|
784
824
|
end
|
785
825
|
end
|