rspec-mocks 2.6.0 → 2.7.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/README.md +0 -19
- data/features/Scope.md +17 -0
- data/features/argument_matchers/README.md +27 -0
- data/features/argument_matchers/explicit.feature +60 -0
- data/features/argument_matchers/general_matchers.feature +85 -0
- data/features/argument_matchers/type_matchers.feature +25 -0
- data/features/message_expectations/any_instance.feature +2 -0
- data/features/message_expectations/receive_counts.feature +209 -0
- data/features/method_stubs/README.md +6 -10
- data/features/method_stubs/any_instance.feature +111 -1
- data/features/method_stubs/simple_return_value.feature +34 -25
- data/features/method_stubs/stub_implementation.feature +1 -1
- data/features/method_stubs/to_ary.feature +12 -10
- data/features/support/env.rb +1 -1
- data/lib/rspec/mocks/any_instance/chain.rb +49 -0
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +33 -0
- data/lib/rspec/mocks/any_instance/message_chains.rb +48 -0
- data/lib/rspec/mocks/any_instance/recorder.rb +168 -0
- data/lib/rspec/mocks/any_instance/stub_chain.rb +35 -0
- data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +34 -0
- data/lib/rspec/mocks/any_instance.rb +8 -235
- data/lib/rspec/mocks/argument_expectation.rb +1 -1
- data/lib/rspec/mocks/argument_matchers.rb +19 -25
- data/lib/rspec/mocks/extensions/marshal.rb +1 -1
- data/lib/rspec/mocks/extensions/psych.rb +1 -1
- data/lib/rspec/mocks/message_expectation.rb +7 -4
- data/lib/rspec/mocks/methods.rb +6 -8
- data/lib/rspec/mocks/mock.rb +2 -2
- data/lib/rspec/mocks/proxy.rb +4 -4
- data/lib/rspec/mocks/version.rb +4 -4
- data/lib/rspec/mocks.rb +13 -14
- data/spec/rspec/mocks/any_instance/message_chains_spec.rb +40 -0
- data/spec/rspec/mocks/any_instance_spec.rb +219 -24
- data/spec/rspec/mocks/any_number_of_times_spec.rb +2 -2
- data/spec/rspec/mocks/argument_expectation_spec.rb +15 -3
- data/spec/rspec/mocks/at_least_spec.rb +1 -1
- data/spec/rspec/mocks/at_most_spec.rb +1 -1
- data/spec/rspec/mocks/bug_report_10263_spec.rb +1 -1
- data/spec/rspec/mocks/bug_report_7611_spec.rb +1 -1
- data/spec/rspec/mocks/bug_report_8165_spec.rb +2 -2
- data/spec/rspec/mocks/bug_report_957_spec.rb +2 -2
- data/spec/rspec/mocks/failing_argument_matchers_spec.rb +1 -1
- data/spec/rspec/mocks/hash_including_matcher_spec.rb +11 -11
- data/spec/rspec/mocks/hash_not_including_matcher_spec.rb +6 -6
- data/spec/rspec/mocks/mock_spec.rb +49 -43
- data/spec/rspec/mocks/multiple_return_value_spec.rb +26 -26
- data/spec/rspec/mocks/partial_mock_spec.rb +3 -2
- data/spec/rspec/mocks/partial_mock_using_mocks_directly_spec.rb +1 -0
- data/spec/rspec/mocks/passing_argument_matchers_spec.rb +3 -3
- data/spec/rspec/mocks/precise_counts_spec.rb +1 -1
- data/spec/rspec/mocks/serialization_spec.rb +7 -2
- data/spec/rspec/mocks/stub_implementation_spec.rb +6 -6
- data/spec/rspec/mocks/stub_spec.rb +6 -6
- data/spec/rspec/mocks/to_ary_spec.rb +9 -0
- metadata +45 -42
- data/.autotest +0 -7
- data/.document +0 -5
- data/.gitignore +0 -10
- data/.travis.yml +0 -7
- data/Gemfile +0 -40
- data/Guardfile +0 -8
- data/License.txt +0 -22
- data/Rakefile +0 -75
- data/autotest/discover.rb +0 -1
- data/cucumber.yml +0 -2
- data/features/.nav +0 -17
- data/features/Changelog.md +0 -80
- data/rspec-mocks.gemspec +0 -25
- data/specs.watchr +0 -57
|
@@ -1,245 +1,18 @@
|
|
|
1
|
+
require 'rspec/mocks/any_instance/chain'
|
|
2
|
+
require 'rspec/mocks/any_instance/stub_chain'
|
|
3
|
+
require 'rspec/mocks/any_instance/stub_chain_chain'
|
|
4
|
+
require 'rspec/mocks/any_instance/expectation_chain'
|
|
5
|
+
require 'rspec/mocks/any_instance/message_chains'
|
|
6
|
+
require 'rspec/mocks/any_instance/recorder'
|
|
7
|
+
|
|
1
8
|
module RSpec
|
|
2
9
|
module Mocks
|
|
3
10
|
module AnyInstance
|
|
4
|
-
class Chain
|
|
5
|
-
[
|
|
6
|
-
:with, :and_return, :and_raise, :and_yield,
|
|
7
|
-
:once, :twice, :any_number_of_times,
|
|
8
|
-
:exactly, :times, :never,
|
|
9
|
-
:at_least, :at_most
|
|
10
|
-
].each do |method_name|
|
|
11
|
-
class_eval(<<-EOM, __FILE__, __LINE__)
|
|
12
|
-
def #{method_name}(*args, &block)
|
|
13
|
-
record(:#{method_name}, *args, &block)
|
|
14
|
-
end
|
|
15
|
-
EOM
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def playback!(instance)
|
|
19
|
-
messages.inject(instance) do |instance, message|
|
|
20
|
-
instance.send(*message.first, &message.last)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def constrained_to_any_of?(*constraints)
|
|
25
|
-
constraints.any? do |constraint|
|
|
26
|
-
messages.any? do |message|
|
|
27
|
-
message.first.first == constraint
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
private
|
|
33
|
-
def messages
|
|
34
|
-
@messages ||= []
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def last_message
|
|
38
|
-
messages.last.first.first unless messages.empty?
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def record(rspec_method_name, *args, &block)
|
|
42
|
-
verify_invocation_order(rspec_method_name, *args, &block)
|
|
43
|
-
messages << [args.unshift(rspec_method_name), block]
|
|
44
|
-
self
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
class StubChain < Chain
|
|
49
|
-
def initialize(*args, &block)
|
|
50
|
-
record(:stub, *args, &block)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def invocation_order
|
|
54
|
-
@invocation_order ||= {
|
|
55
|
-
:stub => [nil],
|
|
56
|
-
:with => [:stub],
|
|
57
|
-
:and_return => [:with, :stub],
|
|
58
|
-
:and_raise => [:with, :stub],
|
|
59
|
-
:and_yield => [:with, :stub]
|
|
60
|
-
}
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def expectation_filfilled?
|
|
64
|
-
true
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
private
|
|
68
|
-
def verify_invocation_order(rspec_method_name, *args, &block)
|
|
69
|
-
unless invocation_order[rspec_method_name].include?(last_message)
|
|
70
|
-
raise(NoMethodError, "Undefined method #{rspec_method_name}")
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
class ExpectationChain < Chain
|
|
76
|
-
def initialize(*args, &block)
|
|
77
|
-
record(:should_receive, *args, &block)
|
|
78
|
-
@expectation_fulfilled = false
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def invocation_order
|
|
82
|
-
@invocation_order ||= {
|
|
83
|
-
:should_receive => [nil],
|
|
84
|
-
:with => [:should_receive],
|
|
85
|
-
:and_return => [:with, :should_receive],
|
|
86
|
-
:and_raise => [:with, :should_receive]
|
|
87
|
-
}
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def expectation_fulfilled!
|
|
91
|
-
@expectation_fulfilled = true
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def expectation_filfilled?
|
|
95
|
-
@expectation_fulfilled || constrained_to_any_of?(:never, :any_number_of_times)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
private
|
|
99
|
-
def verify_invocation_order(rspec_method_name, *args, &block)
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
class Recorder
|
|
104
|
-
def initialize(klass)
|
|
105
|
-
@message_chains = {}
|
|
106
|
-
@observed_methods = []
|
|
107
|
-
@played_methods = {}
|
|
108
|
-
@klass = klass
|
|
109
|
-
@expectation_set = false
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def stub(method_name, *args, &block)
|
|
113
|
-
observe!(method_name)
|
|
114
|
-
@message_chains[method_name] = StubChain.new(method_name, *args, &block)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def should_receive(method_name, *args, &block)
|
|
118
|
-
observe!(method_name)
|
|
119
|
-
@expectation_set = true
|
|
120
|
-
@message_chains[method_name] = ExpectationChain.new(method_name, *args, &block)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def stop_all_observation!
|
|
124
|
-
@observed_methods.each do |method_name|
|
|
125
|
-
restore_method!(method_name)
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def playback!(instance, method_name)
|
|
130
|
-
RSpec::Mocks::space.add(instance)
|
|
131
|
-
@message_chains[method_name].playback!(instance)
|
|
132
|
-
@played_methods[method_name] = instance
|
|
133
|
-
received_expected_message!(method_name) if has_expectation?(method_name)
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def instance_that_received(method_name)
|
|
137
|
-
@played_methods[method_name]
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def verify
|
|
141
|
-
if @expectation_set && !each_expectation_filfilled?
|
|
142
|
-
raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{unfulfilled_expectations.sort.join(', ')}"
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
private
|
|
147
|
-
def each_expectation_filfilled?
|
|
148
|
-
@message_chains.all? do |method_name, chain|
|
|
149
|
-
chain.expectation_filfilled?
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def has_expectation?(method_name)
|
|
154
|
-
@message_chains[method_name].is_a?(ExpectationChain)
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def unfulfilled_expectations
|
|
158
|
-
@message_chains.map do |method_name, chain|
|
|
159
|
-
method_name.to_s if chain.is_a?(ExpectationChain) unless chain.expectation_filfilled?
|
|
160
|
-
end.compact
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
def received_expected_message!(method_name)
|
|
164
|
-
@message_chains[method_name].expectation_fulfilled!
|
|
165
|
-
restore_method!(method_name)
|
|
166
|
-
mark_invoked!(method_name)
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def restore_method!(method_name)
|
|
170
|
-
if @klass.method_defined?(build_alias_method_name(method_name))
|
|
171
|
-
restore_original_method!(method_name)
|
|
172
|
-
else
|
|
173
|
-
remove_dummy_method!(method_name)
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def build_alias_method_name(method_name)
|
|
178
|
-
"__#{method_name}_without_any_instance__"
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
def restore_original_method!(method_name)
|
|
182
|
-
alias_method_name = build_alias_method_name(method_name)
|
|
183
|
-
@klass.class_eval do
|
|
184
|
-
alias_method method_name, alias_method_name
|
|
185
|
-
remove_method alias_method_name
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def remove_dummy_method!(method_name)
|
|
190
|
-
@klass.class_eval do
|
|
191
|
-
remove_method method_name
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
def backup_method!(method_name)
|
|
196
|
-
alias_method_name = build_alias_method_name(method_name)
|
|
197
|
-
@klass.class_eval do
|
|
198
|
-
if method_defined?(method_name)
|
|
199
|
-
alias_method alias_method_name, method_name
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def stop_observing!(method_name)
|
|
205
|
-
restore_method!(method_name)
|
|
206
|
-
@observed_methods.delete(method_name)
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def already_observing?(method_name)
|
|
210
|
-
@observed_methods.include?(method_name)
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def observe!(method_name)
|
|
214
|
-
stop_observing!(method_name) if already_observing?(method_name)
|
|
215
|
-
@observed_methods << method_name
|
|
216
|
-
backup_method!(method_name)
|
|
217
|
-
@klass.class_eval(<<-EOM, __FILE__, __LINE__)
|
|
218
|
-
def #{method_name}(*args, &blk)
|
|
219
|
-
self.class.__recorder.playback!(self, :#{method_name})
|
|
220
|
-
self.send(:#{method_name}, *args, &blk)
|
|
221
|
-
end
|
|
222
|
-
EOM
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def mark_invoked!(method_name)
|
|
226
|
-
backup_method!(method_name)
|
|
227
|
-
@klass.class_eval(<<-EOM, __FILE__, __LINE__)
|
|
228
|
-
def #{method_name}(*args, &blk)
|
|
229
|
-
method_name = :#{method_name}
|
|
230
|
-
current_instance = self
|
|
231
|
-
invoked_instance = self.class.__recorder.instance_that_received(method_name)
|
|
232
|
-
raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by \#{self.inspect} but has already been received by \#{invoked_instance}"
|
|
233
|
-
end
|
|
234
|
-
EOM
|
|
235
|
-
end
|
|
236
|
-
end
|
|
237
|
-
|
|
238
11
|
def any_instance
|
|
239
12
|
RSpec::Mocks::space.add(self)
|
|
240
13
|
__recorder
|
|
241
14
|
end
|
|
242
|
-
|
|
15
|
+
|
|
243
16
|
def rspec_verify
|
|
244
17
|
__recorder.verify
|
|
245
18
|
super
|
|
@@ -26,7 +26,7 @@ module RSpec
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def is_matcher?(obj)
|
|
29
|
-
!null_object?(obj) & obj.respond_to?(:matches?) & obj.respond_to?(
|
|
29
|
+
!null_object?(obj) & obj.respond_to?(:matches?) & [:failure_message_for_should, :failure_message].any? { |m| obj.respond_to?(m) }
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def args_match?(*args)
|
|
@@ -138,48 +138,41 @@ module RSpec
|
|
|
138
138
|
end
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
-
# :call-seq:
|
|
142
|
-
# object.should_receive(:message).with(any_args())
|
|
143
|
-
#
|
|
144
141
|
# Passes if object receives :message with any args at all. This is
|
|
145
142
|
# really a more explicit variation of object.should_receive(:message)
|
|
143
|
+
#
|
|
144
|
+
# == Examples
|
|
145
|
+
# object.should_receive(:message).with(any_args())
|
|
146
146
|
def any_args
|
|
147
147
|
AnyArgsMatcher.new
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
-
# :call-seq:
|
|
151
|
-
# object.should_receive(:message).with(anything())
|
|
152
|
-
#
|
|
153
150
|
# Passes as long as there is an argument.
|
|
151
|
+
#
|
|
152
|
+
# == Examples
|
|
153
|
+
# object.should_receive(:message).with(anything())
|
|
154
154
|
def anything
|
|
155
155
|
AnyArgMatcher.new(nil)
|
|
156
156
|
end
|
|
157
157
|
|
|
158
|
-
# :call-seq:
|
|
159
|
-
# object.should_receive(:message).with(no_args)
|
|
160
|
-
#
|
|
161
158
|
# Passes if no arguments are passed along with the message
|
|
159
|
+
#
|
|
160
|
+
# == Examples
|
|
161
|
+
# object.should_receive(:message).with(no_args)
|
|
162
162
|
def no_args
|
|
163
163
|
NoArgsMatcher.new
|
|
164
164
|
end
|
|
165
165
|
|
|
166
|
-
# :call-seq:
|
|
167
|
-
# object.should_receive(:message).with(duck_type(:hello))
|
|
168
|
-
# object.should_receive(:message).with(duck_type(:hello, :goodbye))
|
|
169
|
-
#
|
|
170
166
|
# Passes if the argument responds to the specified messages.
|
|
171
167
|
#
|
|
172
168
|
# == Examples
|
|
173
|
-
#
|
|
174
|
-
#
|
|
175
|
-
# display = double('display')
|
|
176
|
-
# display.should_receive(:present_names).with(duck_type(:length, :each))
|
|
177
|
-
# => passes
|
|
169
|
+
# object.should_receive(:message).with(duck_type(:hello))
|
|
170
|
+
# object.should_receive(:message).with(duck_type(:hello, :goodbye))
|
|
178
171
|
def duck_type(*args)
|
|
179
172
|
DuckTypeMatcher.new(*args)
|
|
180
173
|
end
|
|
181
174
|
|
|
182
|
-
#
|
|
175
|
+
# == Examples
|
|
183
176
|
# object.should_receive(:message).with(boolean())
|
|
184
177
|
#
|
|
185
178
|
# Passes if the argument is boolean.
|
|
@@ -187,22 +180,23 @@ module RSpec
|
|
|
187
180
|
BooleanMatcher.new(nil)
|
|
188
181
|
end
|
|
189
182
|
|
|
190
|
-
#
|
|
183
|
+
# Passes if the argument is a hash that includes the specified key(s) or key/value
|
|
184
|
+
# pairs. If the hash includes other keys, it will still pass.
|
|
185
|
+
#
|
|
186
|
+
# == Examples
|
|
191
187
|
# object.should_receive(:message).with(hash_including(:key => val))
|
|
192
188
|
# object.should_receive(:message).with(hash_including(:key))
|
|
193
189
|
# object.should_receive(:message).with(hash_including(:key, :key2 => val2))
|
|
194
|
-
# Passes if the argument is a hash that includes the specified key(s) or key/value
|
|
195
|
-
# pairs. If the hash includes other keys, it will still pass.
|
|
196
190
|
def hash_including(*args)
|
|
197
191
|
HashIncludingMatcher.new(anythingize_lonely_keys(*args))
|
|
198
192
|
end
|
|
199
193
|
|
|
200
|
-
#
|
|
194
|
+
# Passes if the argument is a hash that doesn't include the specified key(s) or key/value
|
|
195
|
+
#
|
|
196
|
+
# == Examples
|
|
201
197
|
# object.should_receive(:message).with(hash_not_including(:key => val))
|
|
202
198
|
# object.should_receive(:message).with(hash_not_including(:key))
|
|
203
199
|
# object.should_receive(:message).with(hash_not_including(:key, :key2 => :val2))
|
|
204
|
-
#
|
|
205
|
-
# Passes if the argument is a hash that doesn't include the specified key(s) or key/value
|
|
206
200
|
def hash_not_including(*args)
|
|
207
201
|
HashNotIncludingMatcher.new(anythingize_lonely_keys(*args))
|
|
208
202
|
end
|
|
@@ -7,7 +7,7 @@ module Marshal
|
|
|
7
7
|
mp = object.instance_variable_get(:@mock_proxy)
|
|
8
8
|
return dump_without_mocks(*args.unshift(object)) unless mp.is_a?(::RSpec::Mocks::Proxy)
|
|
9
9
|
|
|
10
|
-
object.
|
|
10
|
+
object.__send__(:remove_instance_variable, :@mock_proxy)
|
|
11
11
|
|
|
12
12
|
begin
|
|
13
13
|
dump_without_mocks(*args.unshift(object.dup))
|
|
@@ -7,7 +7,7 @@ if defined?(Psych) && Psych.respond_to?(:dump)
|
|
|
7
7
|
mp = object.instance_variable_get(:@mock_proxy)
|
|
8
8
|
return dump_without_mocks(object, *args) unless mp.is_a?(::RSpec::Mocks::Proxy)
|
|
9
9
|
|
|
10
|
-
object.
|
|
10
|
+
object.__send__(:remove_instance_variable, :@mock_proxy)
|
|
11
11
|
|
|
12
12
|
begin
|
|
13
13
|
dump_without_mocks(object, *args)
|
|
@@ -63,10 +63,8 @@ module RSpec
|
|
|
63
63
|
@return_block = block_given? ? return_block : lambda { value }
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
# and_raise(Exception) #any exception class
|
|
69
|
-
# and_raise(exception) #any exception object
|
|
66
|
+
# Tells the mock or stub to raise an exception when the message
|
|
67
|
+
# is received.
|
|
70
68
|
#
|
|
71
69
|
# == Warning
|
|
72
70
|
#
|
|
@@ -74,6 +72,11 @@ module RSpec
|
|
|
74
72
|
# raise an instance of it, creating it with +new+. If the exception
|
|
75
73
|
# class initializer requires any parameters, you must pass in an
|
|
76
74
|
# instance and not the class.
|
|
75
|
+
#
|
|
76
|
+
# == Examples
|
|
77
|
+
# and_raise()
|
|
78
|
+
# and_raise(Exception) #any exception class
|
|
79
|
+
# and_raise(exception) #any exception object
|
|
77
80
|
def and_raise(exception=Exception)
|
|
78
81
|
@exception_to_raise = exception
|
|
79
82
|
end
|
data/lib/rspec/mocks/methods.rb
CHANGED
|
@@ -11,7 +11,7 @@ module RSpec
|
|
|
11
11
|
|
|
12
12
|
def stub(sym_or_hash, opts={}, &block)
|
|
13
13
|
if Hash === sym_or_hash
|
|
14
|
-
sym_or_hash.each {|method, value| stub
|
|
14
|
+
sym_or_hash.each {|method, value| stub(method).and_return value }
|
|
15
15
|
else
|
|
16
16
|
__mock_proxy.add_stub(caller(1)[0], sym_or_hash.to_sym, opts, &block)
|
|
17
17
|
end
|
|
@@ -24,15 +24,13 @@ module RSpec
|
|
|
24
24
|
alias_method :stub!, :stub
|
|
25
25
|
alias_method :unstub!, :unstub
|
|
26
26
|
|
|
27
|
-
# :call-seq:
|
|
28
|
-
# double.stub_chain("foo.bar") { :baz }
|
|
29
|
-
# double.stub_chain(:foo, :bar) { :baz }
|
|
30
|
-
#
|
|
31
27
|
# Stubs a chain of methods. Especially useful with fluent and/or
|
|
32
28
|
# composable interfaces.
|
|
33
29
|
#
|
|
34
30
|
# == Examples
|
|
35
31
|
#
|
|
32
|
+
# double.stub_chain("foo.bar") { :baz }
|
|
33
|
+
# double.stub_chain(:foo, :bar) { :baz }
|
|
36
34
|
# Article.stub_chain("recent.published") { [Article.new] }
|
|
37
35
|
def stub_chain(*chain, &blk)
|
|
38
36
|
chain, blk = format_chain(*chain, &blk)
|
|
@@ -50,15 +48,15 @@ module RSpec
|
|
|
50
48
|
end
|
|
51
49
|
end
|
|
52
50
|
|
|
53
|
-
def received_message?(sym, *args, &block)
|
|
51
|
+
def received_message?(sym, *args, &block)
|
|
54
52
|
__mock_proxy.received_message?(sym.to_sym, *args, &block)
|
|
55
53
|
end
|
|
56
54
|
|
|
57
|
-
def rspec_verify
|
|
55
|
+
def rspec_verify
|
|
58
56
|
__mock_proxy.verify
|
|
59
57
|
end
|
|
60
58
|
|
|
61
|
-
def rspec_reset
|
|
59
|
+
def rspec_reset
|
|
62
60
|
__mock_proxy.reset
|
|
63
61
|
end
|
|
64
62
|
|
data/lib/rspec/mocks/mock.rb
CHANGED
|
@@ -35,7 +35,7 @@ module RSpec
|
|
|
35
35
|
alias_method :to_str, :to_s
|
|
36
36
|
|
|
37
37
|
def respond_to?(sym, incl_private=false)
|
|
38
|
-
__mock_proxy.null_object? ? true : super
|
|
38
|
+
__mock_proxy.null_object? && sym != :to_ary ? true : super
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
private
|
|
@@ -70,7 +70,7 @@ module RSpec
|
|
|
70
70
|
|
|
71
71
|
def assign_stubs(stubs)
|
|
72
72
|
stubs.each_pair do |message, response|
|
|
73
|
-
stub
|
|
73
|
+
stub(message).and_return(response)
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
end
|
data/lib/rspec/mocks/proxy.rb
CHANGED
|
@@ -45,11 +45,11 @@ module RSpec
|
|
|
45
45
|
@object
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def already_proxied_respond_to
|
|
48
|
+
def already_proxied_respond_to
|
|
49
49
|
@already_proxied_respond_to = true
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
def already_proxied_respond_to?
|
|
52
|
+
def already_proxied_respond_to?
|
|
53
53
|
@already_proxied_respond_to
|
|
54
54
|
end
|
|
55
55
|
|
|
@@ -69,7 +69,7 @@ module RSpec
|
|
|
69
69
|
method_double[method_name].remove_stub
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
def verify
|
|
72
|
+
def verify
|
|
73
73
|
method_doubles.each {|d| d.verify}
|
|
74
74
|
ensure
|
|
75
75
|
reset
|
|
@@ -110,7 +110,7 @@ module RSpec
|
|
|
110
110
|
stub.advise(*args)
|
|
111
111
|
raise_unexpected_message_args_error(stub, *args)
|
|
112
112
|
elsif @object.is_a?(Class)
|
|
113
|
-
@object.superclass.
|
|
113
|
+
@object.superclass.__send__(method_name, *args, &block)
|
|
114
114
|
else
|
|
115
115
|
@object.__send__(:method_missing, method_name, *args, &block)
|
|
116
116
|
end
|
data/lib/rspec/mocks/version.rb
CHANGED
data/lib/rspec/mocks.rb
CHANGED
|
@@ -17,7 +17,7 @@ module RSpec
|
|
|
17
17
|
#
|
|
18
18
|
# book = double("book")
|
|
19
19
|
# double.stub(:title) { "The RSpec Book" }
|
|
20
|
-
# double.title => "The RSpec Book"
|
|
20
|
+
# double.title # => "The RSpec Book"
|
|
21
21
|
#
|
|
22
22
|
# When we declare a stub, we say we are "stubbing" a method.
|
|
23
23
|
#
|
|
@@ -37,9 +37,9 @@ module RSpec
|
|
|
37
37
|
# == Mock Objects and Test Stubs
|
|
38
38
|
#
|
|
39
39
|
# The names Mock Object and Test Stub suggest specialized Test Doubles. i.e.
|
|
40
|
-
# Test Stub
|
|
41
|
-
# Object
|
|
42
|
-
#
|
|
40
|
+
# a Test Stub is a Test Double that only supports method stubs, and a Mock
|
|
41
|
+
# Object is a Test Double that supports message expectations and method
|
|
42
|
+
# stubs.
|
|
43
43
|
#
|
|
44
44
|
# There is a lot of overlapping nomenclature here, and there are many
|
|
45
45
|
# variations of these patterns (fakes, spies, etc). Keep in mind that most of
|
|
@@ -60,7 +60,7 @@ module RSpec
|
|
|
60
60
|
#
|
|
61
61
|
# In this case we're instrumenting Person to return the person object we've
|
|
62
62
|
# defined whenever it receives the +find+ message. We can do this with any
|
|
63
|
-
# object in a system because
|
|
63
|
+
# object in a system because rspec-mocks adds the +stub+ and +should_receive+
|
|
64
64
|
# methods to every object. When we use either, RSpec replaces the method
|
|
65
65
|
# we're stubbing or mocking with it's own test-double-like method. At the
|
|
66
66
|
# end of the example, RSpec verifies any message expectations, and then
|
|
@@ -73,15 +73,14 @@ module RSpec
|
|
|
73
73
|
#
|
|
74
74
|
# == Argument Matchers
|
|
75
75
|
#
|
|
76
|
-
# Arguments that are passed to
|
|
77
|
-
# using
|
|
78
|
-
# rather than the arguments themselves, you can use any of
|
|
79
|
-
# They don't all make syntactic
|
|
80
|
-
#
|
|
76
|
+
# Arguments that are passed to +with+ are compared with actual arguments
|
|
77
|
+
# received using ==. In cases in which you want to specify things about the
|
|
78
|
+
# arguments rather than the arguments themselves, you can use any of the
|
|
79
|
+
# matchers that ship with rspec-expectations. They don't all make syntactic
|
|
80
|
+
# sense (they were primarily designed for use with RSpec::Expectations), but
|
|
81
|
+
# you are free to create your own custom RSpec::Matchers.
|
|
81
82
|
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
# In addition, RSpec::Mocks adds some keyword Symbols that you can use to
|
|
83
|
+
# rspec-mocks also adds some keyword Symbols that you can use to
|
|
85
84
|
# specify certain kinds of arguments:
|
|
86
85
|
#
|
|
87
86
|
# double.should_receive(:msg).with(no_args())
|
|
@@ -152,7 +151,7 @@ module RSpec
|
|
|
152
151
|
#
|
|
153
152
|
# double.should_receive(:msg) do |arg|
|
|
154
153
|
# arg.should be_an_istance_of(Array)
|
|
155
|
-
# arg.length.should
|
|
154
|
+
# arg.length.should eq 7
|
|
156
155
|
# end
|
|
157
156
|
#
|
|
158
157
|
# == Combining Expectation Details
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe RSpec::Mocks::AnyInstance::MessageChains do
|
|
4
|
+
let(:chains) { RSpec::Mocks::AnyInstance::MessageChains.new }
|
|
5
|
+
let(:stub_chain) { RSpec::Mocks::AnyInstance::StubChain.new }
|
|
6
|
+
let(:expectation_chain) { RSpec::Mocks::AnyInstance::ExpectationChain.new }
|
|
7
|
+
|
|
8
|
+
it "knows if a method does not have an expectation set on it" do
|
|
9
|
+
chains.add(:method_name, stub_chain)
|
|
10
|
+
chains.has_expectation?(:method_name).should be_false
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "knows if a method has an expectation set on it" do
|
|
14
|
+
chains.add(:method_name, stub_chain)
|
|
15
|
+
chains.add(:method_name, expectation_chain)
|
|
16
|
+
chains.has_expectation?(:method_name).should be_true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "can remove all stub chains" do
|
|
20
|
+
chains.add(:method_name, stub_chain)
|
|
21
|
+
chains.add(:method_name, expectation_chain)
|
|
22
|
+
chains.add(:method_name, another_stub_chain = RSpec::Mocks::AnyInstance::StubChain.new)
|
|
23
|
+
|
|
24
|
+
chains.remove_stub_chains_for!(:method_name)
|
|
25
|
+
chains[:method_name].should eq([expectation_chain])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "creating stub chains" do
|
|
29
|
+
it "understands how to add a stub chain for a method" do
|
|
30
|
+
chains.add(:method_name, stub_chain)
|
|
31
|
+
chains[:method_name].should eq([stub_chain])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "allows multiple stub chains for a method" do
|
|
35
|
+
chains.add(:method_name, stub_chain)
|
|
36
|
+
chains.add(:method_name, another_stub_chain = RSpec::Mocks::AnyInstance::StubChain.new)
|
|
37
|
+
chains[:method_name].should eq([stub_chain, another_stub_chain])
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|