rspec-mocks 3.8.1
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +3 -0
- data/.document +5 -0
- data/.yardopts +6 -0
- data/Changelog.md +1108 -0
- data/LICENSE.md +25 -0
- data/README.md +460 -0
- data/lib/rspec/mocks.rb +130 -0
- data/lib/rspec/mocks/any_instance.rb +11 -0
- data/lib/rspec/mocks/any_instance/chain.rb +110 -0
- data/lib/rspec/mocks/any_instance/error_generator.rb +31 -0
- data/lib/rspec/mocks/any_instance/expect_chain_chain.rb +31 -0
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +50 -0
- data/lib/rspec/mocks/any_instance/message_chains.rb +83 -0
- data/lib/rspec/mocks/any_instance/proxy.rb +116 -0
- data/lib/rspec/mocks/any_instance/recorder.rb +289 -0
- data/lib/rspec/mocks/any_instance/stub_chain.rb +51 -0
- data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +23 -0
- data/lib/rspec/mocks/argument_list_matcher.rb +100 -0
- data/lib/rspec/mocks/argument_matchers.rb +320 -0
- data/lib/rspec/mocks/configuration.rb +212 -0
- data/lib/rspec/mocks/error_generator.rb +369 -0
- data/lib/rspec/mocks/example_methods.rb +434 -0
- data/lib/rspec/mocks/instance_method_stasher.rb +146 -0
- data/lib/rspec/mocks/marshal_extension.rb +41 -0
- data/lib/rspec/mocks/matchers/expectation_customization.rb +20 -0
- data/lib/rspec/mocks/matchers/have_received.rb +134 -0
- data/lib/rspec/mocks/matchers/receive.rb +132 -0
- data/lib/rspec/mocks/matchers/receive_message_chain.rb +82 -0
- data/lib/rspec/mocks/matchers/receive_messages.rb +77 -0
- data/lib/rspec/mocks/message_chain.rb +87 -0
- data/lib/rspec/mocks/message_expectation.rb +741 -0
- data/lib/rspec/mocks/method_double.rb +287 -0
- data/lib/rspec/mocks/method_reference.rb +202 -0
- data/lib/rspec/mocks/minitest_integration.rb +68 -0
- data/lib/rspec/mocks/mutate_const.rb +339 -0
- data/lib/rspec/mocks/object_reference.rb +149 -0
- data/lib/rspec/mocks/order_group.rb +81 -0
- data/lib/rspec/mocks/proxy.rb +485 -0
- data/lib/rspec/mocks/space.rb +238 -0
- data/lib/rspec/mocks/standalone.rb +3 -0
- data/lib/rspec/mocks/syntax.rb +325 -0
- data/lib/rspec/mocks/targets.rb +124 -0
- data/lib/rspec/mocks/test_double.rb +171 -0
- data/lib/rspec/mocks/verifying_double.rb +129 -0
- data/lib/rspec/mocks/verifying_message_expectation.rb +54 -0
- data/lib/rspec/mocks/verifying_proxy.rb +220 -0
- data/lib/rspec/mocks/version.rb +9 -0
- metadata +221 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,116 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Mocks
|
3
|
+
module AnyInstance
|
4
|
+
# @private
|
5
|
+
# The `AnyInstance::Recorder` is responsible for redefining the klass's
|
6
|
+
# instance method in order to add any stubs/expectations the first time
|
7
|
+
# the method is called. It's not capable of updating a stub on an instance
|
8
|
+
# that's already been previously stubbed (either directly, or via
|
9
|
+
# `any_instance`).
|
10
|
+
#
|
11
|
+
# This proxy sits in front of the recorder and delegates both to it
|
12
|
+
# and to the `RSpec::Mocks::Proxy` for each already mocked or stubbed
|
13
|
+
# instance of the class, in order to propogates changes to the instances.
|
14
|
+
#
|
15
|
+
# Note that unlike `RSpec::Mocks::Proxy`, this proxy class is stateless
|
16
|
+
# and is not persisted in `RSpec::Mocks.space`.
|
17
|
+
#
|
18
|
+
# Proxying for the message expectation fluent interface (typically chained
|
19
|
+
# off of the return value of one of these methods) is provided by the
|
20
|
+
# `FluentInterfaceProxy` class below.
|
21
|
+
class Proxy
|
22
|
+
def initialize(recorder, target_proxies)
|
23
|
+
@recorder = recorder
|
24
|
+
@target_proxies = target_proxies
|
25
|
+
end
|
26
|
+
|
27
|
+
def klass
|
28
|
+
@recorder.klass
|
29
|
+
end
|
30
|
+
|
31
|
+
def stub(method_name_or_method_map, &block)
|
32
|
+
if Hash === method_name_or_method_map
|
33
|
+
method_name_or_method_map.each do |method_name, return_value|
|
34
|
+
stub(method_name).and_return(return_value)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
perform_proxying(__method__, [method_name_or_method_map], block) do |proxy|
|
38
|
+
proxy.add_stub(method_name_or_method_map, &block)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def unstub(method_name)
|
44
|
+
perform_proxying(__method__, [method_name], nil) do |proxy|
|
45
|
+
proxy.remove_stub_if_present(method_name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def stub_chain(*chain, &block)
|
50
|
+
perform_proxying(__method__, chain, block) do |proxy|
|
51
|
+
Mocks::StubChain.stub_chain_on(proxy.object, *chain, &block)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def expect_chain(*chain, &block)
|
56
|
+
perform_proxying(__method__, chain, block) do |proxy|
|
57
|
+
Mocks::ExpectChain.expect_chain_on(proxy.object, *chain, &block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def should_receive(method_name, &block)
|
62
|
+
perform_proxying(__method__, [method_name], block) do |proxy|
|
63
|
+
# Yeah, this is a bit odd...but if we used `add_message_expectation`
|
64
|
+
# then it would act like `expect_every_instance_of(klass).to receive`.
|
65
|
+
# The any_instance recorder takes care of validating that an instance
|
66
|
+
# received the message.
|
67
|
+
proxy.add_stub(method_name, &block)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def should_not_receive(method_name, &block)
|
72
|
+
perform_proxying(__method__, [method_name], block) do |proxy|
|
73
|
+
proxy.add_message_expectation(method_name, &block).never
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def perform_proxying(method_name, args, block, &target_proxy_block)
|
80
|
+
recorder_value = @recorder.__send__(method_name, *args, &block)
|
81
|
+
proxy_values = @target_proxies.map(&target_proxy_block)
|
82
|
+
FluentInterfaceProxy.new([recorder_value] + proxy_values)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# @private
|
87
|
+
# Delegates messages to each of the given targets in order to
|
88
|
+
# provide the fluent interface that is available off of message
|
89
|
+
# expectations when dealing with `any_instance`.
|
90
|
+
#
|
91
|
+
# `targets` will typically contain 1 of the `AnyInstance::Recorder`
|
92
|
+
# return values and N `MessageExpectation` instances (one per instance
|
93
|
+
# of the `any_instance` klass).
|
94
|
+
class FluentInterfaceProxy
|
95
|
+
def initialize(targets)
|
96
|
+
@targets = targets
|
97
|
+
end
|
98
|
+
|
99
|
+
if RUBY_VERSION.to_f > 1.8
|
100
|
+
def respond_to_missing?(method_name, include_private=false)
|
101
|
+
super || @targets.first.respond_to?(method_name, include_private)
|
102
|
+
end
|
103
|
+
else
|
104
|
+
def respond_to?(method_name, include_private=false)
|
105
|
+
super || @targets.first.respond_to?(method_name, include_private)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def method_missing(*args, &block)
|
110
|
+
return_values = @targets.map { |t| t.__send__(*args, &block) }
|
111
|
+
FluentInterfaceProxy.new(return_values)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,289 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Mocks
|
3
|
+
module AnyInstance
|
4
|
+
# Given a class `TheClass`, `TheClass.any_instance` returns a `Recorder`,
|
5
|
+
# which records stubs and message expectations for later playback on
|
6
|
+
# instances of `TheClass`.
|
7
|
+
#
|
8
|
+
# Further constraints are stored in instances of [Chain](Chain).
|
9
|
+
#
|
10
|
+
# @see AnyInstance
|
11
|
+
# @see Chain
|
12
|
+
class Recorder
|
13
|
+
# @private
|
14
|
+
attr_reader :message_chains, :stubs, :klass
|
15
|
+
|
16
|
+
def initialize(klass)
|
17
|
+
@message_chains = MessageChains.new
|
18
|
+
@stubs = Hash.new { |hash, key| hash[key] = [] }
|
19
|
+
@observed_methods = []
|
20
|
+
@played_methods = {}
|
21
|
+
@backed_up_method_owner = {}
|
22
|
+
@klass = klass
|
23
|
+
@expectation_set = false
|
24
|
+
end
|
25
|
+
|
26
|
+
# Initializes the recording a stub to be played back against any
|
27
|
+
# instance of this object that invokes the submitted method.
|
28
|
+
#
|
29
|
+
# @see Methods#stub
|
30
|
+
def stub(method_name, &block)
|
31
|
+
observe!(method_name)
|
32
|
+
message_chains.add(method_name, StubChain.new(self, method_name, &block))
|
33
|
+
end
|
34
|
+
|
35
|
+
# Initializes the recording a stub chain to be played back against any
|
36
|
+
# instance of this object that invokes the method matching the first
|
37
|
+
# argument.
|
38
|
+
#
|
39
|
+
# @see Methods#stub_chain
|
40
|
+
def stub_chain(*method_names_and_optional_return_values, &block)
|
41
|
+
normalize_chain(*method_names_and_optional_return_values) do |method_name, args|
|
42
|
+
observe!(method_name)
|
43
|
+
message_chains.add(method_name, StubChainChain.new(self, *args, &block))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# @private
|
48
|
+
def expect_chain(*method_names_and_optional_return_values, &block)
|
49
|
+
@expectation_set = true
|
50
|
+
normalize_chain(*method_names_and_optional_return_values) do |method_name, args|
|
51
|
+
observe!(method_name)
|
52
|
+
message_chains.add(method_name, ExpectChainChain.new(self, *args, &block))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Initializes the recording a message expectation to be played back
|
57
|
+
# against any instance of this object that invokes the submitted
|
58
|
+
# method.
|
59
|
+
#
|
60
|
+
# @see Methods#should_receive
|
61
|
+
def should_receive(method_name, &block)
|
62
|
+
@expectation_set = true
|
63
|
+
observe!(method_name)
|
64
|
+
message_chains.add(method_name, PositiveExpectationChain.new(self, method_name, &block))
|
65
|
+
end
|
66
|
+
|
67
|
+
# The opposite of `should_receive`
|
68
|
+
#
|
69
|
+
# @see Methods#should_not_receive
|
70
|
+
def should_not_receive(method_name, &block)
|
71
|
+
should_receive(method_name, &block).never
|
72
|
+
end
|
73
|
+
|
74
|
+
# Removes any previously recorded stubs, stub_chains or message
|
75
|
+
# expectations that use `method_name`.
|
76
|
+
#
|
77
|
+
# @see Methods#unstub
|
78
|
+
def unstub(method_name)
|
79
|
+
unless @observed_methods.include?(method_name.to_sym)
|
80
|
+
AnyInstance.error_generator.raise_method_not_stubbed_error(method_name)
|
81
|
+
end
|
82
|
+
message_chains.remove_stub_chains_for!(method_name)
|
83
|
+
stubs[method_name].clear
|
84
|
+
stop_observing!(method_name) unless message_chains.has_expectation?(method_name)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @api private
|
88
|
+
#
|
89
|
+
# Used internally to verify that message expectations have been
|
90
|
+
# fulfilled.
|
91
|
+
def verify
|
92
|
+
return unless @expectation_set
|
93
|
+
return if message_chains.all_expectations_fulfilled?
|
94
|
+
|
95
|
+
AnyInstance.error_generator.raise_second_instance_received_message_error(message_chains.unfulfilled_expectations)
|
96
|
+
end
|
97
|
+
|
98
|
+
# @private
|
99
|
+
def stop_all_observation!
|
100
|
+
@observed_methods.each { |method_name| restore_method!(method_name) }
|
101
|
+
end
|
102
|
+
|
103
|
+
# @private
|
104
|
+
def playback!(instance, method_name)
|
105
|
+
RSpec::Mocks.space.ensure_registered(instance)
|
106
|
+
message_chains.playback!(instance, method_name)
|
107
|
+
@played_methods[method_name] = instance
|
108
|
+
received_expected_message!(method_name) if message_chains.has_expectation?(method_name)
|
109
|
+
end
|
110
|
+
|
111
|
+
# @private
|
112
|
+
def instance_that_received(method_name)
|
113
|
+
@played_methods[method_name]
|
114
|
+
end
|
115
|
+
|
116
|
+
# @private
|
117
|
+
def build_alias_method_name(method_name)
|
118
|
+
"__#{method_name}_without_any_instance__"
|
119
|
+
end
|
120
|
+
|
121
|
+
# @private
|
122
|
+
def already_observing?(method_name)
|
123
|
+
@observed_methods.include?(method_name) || super_class_observing?(method_name)
|
124
|
+
end
|
125
|
+
|
126
|
+
# @private
|
127
|
+
def notify_received_message(_object, message, args, _blk)
|
128
|
+
has_expectation = false
|
129
|
+
|
130
|
+
message_chains.each_unfulfilled_expectation_matching(message, *args) do |expectation|
|
131
|
+
has_expectation = true
|
132
|
+
expectation.expectation_fulfilled!
|
133
|
+
end
|
134
|
+
|
135
|
+
return unless has_expectation
|
136
|
+
|
137
|
+
restore_method!(message)
|
138
|
+
mark_invoked!(message)
|
139
|
+
end
|
140
|
+
|
141
|
+
protected
|
142
|
+
|
143
|
+
def stop_observing!(method_name)
|
144
|
+
restore_method!(method_name)
|
145
|
+
@observed_methods.delete(method_name)
|
146
|
+
super_class_observers_for(method_name).each do |ancestor|
|
147
|
+
::RSpec::Mocks.space.
|
148
|
+
any_instance_recorder_for(ancestor).stop_observing!(method_name)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
def ancestor_is_an_observer?(method_name)
|
155
|
+
lambda do |ancestor|
|
156
|
+
unless ancestor == @klass
|
157
|
+
::RSpec::Mocks.space.
|
158
|
+
any_instance_recorder_for(ancestor).already_observing?(method_name)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def super_class_observers_for(method_name)
|
164
|
+
@klass.ancestors.select(&ancestor_is_an_observer?(method_name))
|
165
|
+
end
|
166
|
+
|
167
|
+
def super_class_observing?(method_name)
|
168
|
+
@klass.ancestors.any?(&ancestor_is_an_observer?(method_name))
|
169
|
+
end
|
170
|
+
|
171
|
+
def normalize_chain(*args)
|
172
|
+
args.shift.to_s.split('.').map { |s| s.to_sym }.reverse.each { |a| args.unshift a }
|
173
|
+
yield args.first, args
|
174
|
+
end
|
175
|
+
|
176
|
+
def received_expected_message!(method_name)
|
177
|
+
message_chains.received_expected_message!(method_name)
|
178
|
+
restore_method!(method_name)
|
179
|
+
mark_invoked!(method_name)
|
180
|
+
end
|
181
|
+
|
182
|
+
def restore_method!(method_name)
|
183
|
+
if public_protected_or_private_method_defined?(build_alias_method_name(method_name))
|
184
|
+
restore_original_method!(method_name)
|
185
|
+
else
|
186
|
+
remove_dummy_method!(method_name)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def restore_original_method!(method_name)
|
191
|
+
return unless @klass.instance_method(method_name).owner == @klass
|
192
|
+
|
193
|
+
alias_method_name = build_alias_method_name(method_name)
|
194
|
+
@klass.class_exec(@backed_up_method_owner) do |backed_up_method_owner|
|
195
|
+
remove_method method_name
|
196
|
+
|
197
|
+
# A @klass can have methods implemented (see Method#owner) in @klass
|
198
|
+
# or inherited from a superclass. In ruby 2.2 and earlier, we can copy
|
199
|
+
# a method regardless of the 'owner' and restore it to @klass after
|
200
|
+
# because a call to 'super' from @klass's copied method would end up
|
201
|
+
# calling the original class's superclass's method.
|
202
|
+
#
|
203
|
+
# With the commit below, available starting in 2.3.0, ruby changed
|
204
|
+
# this behavior and a call to 'super' from the method copied to @klass
|
205
|
+
# will call @klass's superclass method, which is the original
|
206
|
+
# implementer of this method! This leads to very strange errors
|
207
|
+
# if @klass's copied method calls 'super', since it would end up
|
208
|
+
# calling itself, the original method implemented in @klass's
|
209
|
+
# superclass.
|
210
|
+
#
|
211
|
+
# For ruby 2.3 and above, we need to only restore methods that
|
212
|
+
# @klass originally owned.
|
213
|
+
#
|
214
|
+
# https://github.com/ruby/ruby/commit/c8854d2ca4be9ee6946e6d17b0e17d9ef130ee81
|
215
|
+
if RUBY_VERSION < "2.3" || backed_up_method_owner[method_name.to_sym] == self
|
216
|
+
alias_method method_name, alias_method_name
|
217
|
+
end
|
218
|
+
remove_method alias_method_name
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def remove_dummy_method!(method_name)
|
223
|
+
@klass.class_exec do
|
224
|
+
remove_method method_name
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def backup_method!(method_name)
|
229
|
+
return unless public_protected_or_private_method_defined?(method_name)
|
230
|
+
|
231
|
+
alias_method_name = build_alias_method_name(method_name)
|
232
|
+
@backed_up_method_owner[method_name.to_sym] ||= @klass.instance_method(method_name).owner
|
233
|
+
@klass.class_exec do
|
234
|
+
alias_method alias_method_name, method_name
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def public_protected_or_private_method_defined?(method_name)
|
239
|
+
MethodReference.method_defined_at_any_visibility?(@klass, method_name)
|
240
|
+
end
|
241
|
+
|
242
|
+
def observe!(method_name)
|
243
|
+
allow_no_prepended_module_definition_of(method_name)
|
244
|
+
|
245
|
+
if RSpec::Mocks.configuration.verify_partial_doubles? && !Mocks.configuration.temporarily_suppress_partial_double_verification
|
246
|
+
unless public_protected_or_private_method_defined?(method_name)
|
247
|
+
AnyInstance.error_generator.raise_does_not_implement_error(@klass, method_name)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
stop_observing!(method_name) if already_observing?(method_name)
|
252
|
+
@observed_methods << method_name
|
253
|
+
backup_method!(method_name)
|
254
|
+
recorder = self
|
255
|
+
@klass.__send__(:define_method, method_name) do |*args, &blk|
|
256
|
+
recorder.playback!(self, method_name)
|
257
|
+
__send__(method_name, *args, &blk)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def mark_invoked!(method_name)
|
262
|
+
backup_method!(method_name)
|
263
|
+
recorder = self
|
264
|
+
@klass.__send__(:define_method, method_name) do |*_args, &_blk|
|
265
|
+
invoked_instance = recorder.instance_that_received(method_name)
|
266
|
+
inspect = "#<#{self.class}:#{object_id} #{instance_variables.map { |name| "#{name}=#{instance_variable_get name}" }.join(', ')}>"
|
267
|
+
AnyInstance.error_generator.raise_message_already_received_by_other_instance_error(
|
268
|
+
method_name, inspect, invoked_instance
|
269
|
+
)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
if Support::RubyFeatures.module_prepends_supported?
|
274
|
+
def allow_no_prepended_module_definition_of(method_name)
|
275
|
+
prepended_modules = RSpec::Mocks::Proxy.prepended_modules_of(@klass)
|
276
|
+
problem_mod = prepended_modules.find { |mod| mod.method_defined?(method_name) }
|
277
|
+
return unless problem_mod
|
278
|
+
|
279
|
+
AnyInstance.error_generator.raise_not_supported_with_prepend_error(method_name, problem_mod)
|
280
|
+
end
|
281
|
+
else
|
282
|
+
def allow_no_prepended_module_definition_of(_method_name)
|
283
|
+
# nothing to do; prepends aren't supported on this version of ruby
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Mocks
|
3
|
+
module AnyInstance
|
4
|
+
# @private
|
5
|
+
class StubChain < Chain
|
6
|
+
# @private
|
7
|
+
def expectation_fulfilled?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def create_message_expectation_on(instance)
|
14
|
+
proxy = ::RSpec::Mocks.space.proxy_for(instance)
|
15
|
+
method_name, opts = @expectation_args
|
16
|
+
opts = (opts || {}).merge(:expected_form => IGNORED_BACKTRACE_LINE)
|
17
|
+
|
18
|
+
stub = proxy.add_stub(method_name, opts, &@expectation_block)
|
19
|
+
@recorder.stubs[stub.message] << stub
|
20
|
+
|
21
|
+
if RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks?
|
22
|
+
stub.and_yield_receiver_to_implementation
|
23
|
+
end
|
24
|
+
|
25
|
+
stub
|
26
|
+
end
|
27
|
+
|
28
|
+
InvocationOrder =
|
29
|
+
{
|
30
|
+
:and_return => [:with, nil],
|
31
|
+
:and_raise => [:with, nil],
|
32
|
+
:and_yield => [:with, :and_yield, nil],
|
33
|
+
:and_throw => [:with, nil],
|
34
|
+
:and_call_original => [:with, nil],
|
35
|
+
:and_wrap_original => [:with, nil]
|
36
|
+
}.freeze
|
37
|
+
|
38
|
+
EmptyInvocationOrder = {}.freeze
|
39
|
+
|
40
|
+
def invocation_order
|
41
|
+
InvocationOrder
|
42
|
+
end
|
43
|
+
|
44
|
+
def verify_invocation_order(rspec_method_name, *_args, &_block)
|
45
|
+
return if invocation_order.fetch(rspec_method_name, [nil]).include?(last_message)
|
46
|
+
raise NoMethodError, "Undefined method #{rspec_method_name}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|