Class: FlexMock::PartialMockProxy
- Includes:
- Ordering
- Defined in:
- lib/flexmock/partial_mock.rb,
lib/flexmock/deprecated_methods.rb
Overview
PartialMockProxy is used to mate the mock framework to an existing object. The object is “enhanced” with a reference to a mock object (stored in @flexmock_proxy
). When the should_receive
method is sent to the proxy, it overrides the existing object’s method by creating singleton method that forwards to the mock. When testing is complete, PartialMockProxy will erase the mocking infrastructure from the object being mocked (e.g. remove instance variables and mock singleton methods).
Defined Under Namespace
Classes: ProxyBox, ProxyDefinitionModule
Constant Summary collapse
- MOCK_METHODS =
The following methods are added to partial mocks so that they can act like a mock.
[ :should_receive, :new_instances, :should_expect, :should_receive_with_location, :flexmock_get, :flexmock_teardown, :flexmock_verify, :flexmock_received?, :flexmock_calls, :flexmock_find_expectation, :invoke_original ]
Instance Attribute Summary collapse
-
#mock ⇒ Object
readonly
Returns the value of attribute mock.
Class Method Summary collapse
-
.make_proxy_for(obj, container, name, safe_mode) ⇒ Object
Make a partial mock proxy and install it on the target
obj
.
Instance Method Summary collapse
- #add_mock_method(method_name) ⇒ Object
- #any_instance(&block) ⇒ Object deprecated Deprecated.
-
#find_original_method(m) ⇒ Object
Whether the given method’s original definition has been stored.
-
#flexmock_based_on(*args) ⇒ Object
Forward the based on request.
-
#flexmock_calls ⇒ Object
Forward to the mock.
-
#flexmock_container ⇒ Object
Forward to the mock’s container.
-
#flexmock_container=(container) ⇒ Object
Set the proxy’s mock container.
- #flexmock_define_expectation(location, *args, **kw) ⇒ Object
-
#flexmock_expectations_for(method_name) ⇒ Object
Forward the request for the expectation director to the mock.
- #flexmock_find_expectation(*args, **kw, &block) ⇒ Object
-
#flexmock_get ⇒ Object
Get the mock object for the partial mock.
-
#flexmock_invoke_original(method, args, kw, block) ⇒ Object
Invoke the original definition of method on the object supported by the stub.
- #flexmock_plain_new_method?(m) ⇒ Boolean
-
#flexmock_received?(*args, **kw) ⇒ Boolean
Forward to the mock.
-
#flexmock_teardown ⇒ Object
Remove all traces of the mocking framework from the existing object.
-
#flexmock_verify ⇒ Object
Verify that the mock has been properly called.
-
#has_original_method?(m) ⇒ Boolean
Whether the given method’s original definition has been stored.
-
#has_proxied_method?(m) ⇒ Boolean
Whether the given method is already being proxied.
-
#initialize(obj, mock, safe_mode, parent: nil) ⇒ PartialMockProxy
constructor
Initialize a PartialMockProxy object.
-
#initialize_stub(recorder, expectations_block) ⇒ Object
Stubs the #initialize method on a class.
- #initialize_stub? ⇒ Boolean
- #initialize_stub_remove ⇒ Object
-
#invoke_original(m, *args, **kw, &block) ⇒ Object
Invoke the original of a mocked method.
-
#new_instances(*allocators, &block) ⇒ Object
:call-seq: new_instances.should_receive(…) new_instances { |instance| instance.should_receive(…) }.
-
#original_method(m) ⇒ Object
Whether the given method’s original definition has been stored.
- #pop_flexmock_container ⇒ Object
- #push_flexmock_container(container) ⇒ Object
- #should_expect(*args) {|Recorder.new(self)| ... } ⇒ Object
-
#should_receive(*args, **kw) ⇒ Object
:call-seq: should_receive(:method_name) should_receive(:method1, method2, …) should_receive(:meth1 => result1, :meth2 => result2, …).
Methods included from Ordering
#flexmock_allocate_order, #flexmock_current_order, #flexmock_current_order=, #flexmock_groups, #flexmock_validate_order
Constructor Details
#initialize(obj, mock, safe_mode, parent: nil) ⇒ PartialMockProxy
Initialize a PartialMockProxy object.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/flexmock/partial_mock.rb', line 103 def initialize(obj, mock, safe_mode, parent: nil) @obj = obj @mock = mock @proxy_definition_module = nil @parent = parent @initialize_override = nil unless safe_mode add_mock_method(:should_receive) MOCK_METHODS.each do |sym| unless @obj.respond_to?(sym) add_mock_method(sym) end end end end |
Instance Attribute Details
#mock ⇒ Object (readonly)
Returns the value of attribute mock.
29 30 31 |
# File 'lib/flexmock/partial_mock.rb', line 29 def mock @mock end |
Class Method Details
.make_proxy_for(obj, container, name, safe_mode) ⇒ Object
Make a partial mock proxy and install it on the target obj
.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/flexmock/partial_mock.rb', line 70 def self.make_proxy_for(obj, container, name, safe_mode) name ||= "flexmock(#{obj.class.to_s})" if !obj.instance_variable_defined?("@flexmock_proxy") proxy_box = obj.instance_variable_set("@flexmock_proxy", ProxyBox.new) else proxy_box = obj.instance_variable_get("@flexmock_proxy") end if proxy_box.container != container if !proxy_box.empty? parent_proxy, _ = proxy_box.proxy parent_mock = parent_proxy.mock end mock = FlexMock.new(name, container, parent: parent_mock) proxy = PartialMockProxy.new(obj, mock, safe_mode, parent: parent_proxy) proxy_box.push(proxy, container) end proxy_box.proxy end |
Instance Method Details
#add_mock_method(method_name) ⇒ Object
238 239 240 241 242 243 244 245 246 247 |
# File 'lib/flexmock/partial_mock.rb', line 238 def add_mock_method(method_name) proxy_module_eval do define_method(method_name) { |*args, **kw, &block| proxy = __flexmock_proxy or fail "Missing FlexMock proxy " + "(for method_name=#{method_name.inspect}, self=\#{self})" proxy.send(method_name, *args, **kw, &block) } end end |
#any_instance(&block) ⇒ Object
any_instance is present for backwards compatibility with version 0.5.0.
54 55 56 57 |
# File 'lib/flexmock/deprecated_methods.rb', line 54 def any_instance(&block) $stderr.puts "any_instance is deprecated, use new_instances instead." new_instances(&block) end |
#find_original_method(m) ⇒ Object
Whether the given method’s original definition has been stored
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/flexmock/partial_mock.rb', line 169 def find_original_method(m) it = if m.respond_to?(:to_str) || m.respond_to?(:to_sym) @obj.method(m) else m end while it && (it.owner != @proxy_definition_module) it = it.super_method end return unless it while it && it.owner.kind_of?(ProxyDefinitionModule) it = it.super_method end it rescue NameError => e raise unless e.name == m end |
#flexmock_based_on(*args) ⇒ Object
Forward the based on request.
404 405 406 |
# File 'lib/flexmock/partial_mock.rb', line 404 def flexmock_based_on(*args) @mock.flexmock_based_on(*args) end |
#flexmock_calls ⇒ Object
Forward to the mock
389 390 391 |
# File 'lib/flexmock/partial_mock.rb', line 389 def flexmock_calls @mock.flexmock_calls end |
#flexmock_container ⇒ Object
Forward to the mock’s container.
379 380 381 |
# File 'lib/flexmock/partial_mock.rb', line 379 def flexmock_container @mock.flexmock_container end |
#flexmock_container=(container) ⇒ Object
Set the proxy’s mock container. This set value is ignored because the proxy always uses the container of its mock.
395 396 |
# File 'lib/flexmock/partial_mock.rb', line 395 def flexmock_container=(container) end |
#flexmock_define_expectation(location, *args, **kw) ⇒ Object
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/flexmock/partial_mock.rb', line 213 def flexmock_define_expectation(location, *args, **kw) EXP_BUILDER.parse_should_args(self, args, kw) do |method_name| if !has_proxied_method?(method_name) define_proxy_method(method_name) end ex = @mock.flexmock_define_expectation(location, method_name) if FlexMock.partials_verify_signatures if (existing_method = find_original_method(method_name)) if flexmock_plain_new_method?(existing_method) # Look for the signature of `initialize` instead ex.with_signature_matching(@obj.instance_method(:initialize)) else ex.with_signature_matching(existing_method) end end end ex.mock = self ex end end |
#flexmock_expectations_for(method_name) ⇒ Object
Forward the request for the expectation director to the mock.
399 400 401 |
# File 'lib/flexmock/partial_mock.rb', line 399 def flexmock_expectations_for(method_name) @mock.flexmock_expectations_for(method_name) end |
#flexmock_find_expectation(*args, **kw, &block) ⇒ Object
234 235 236 |
# File 'lib/flexmock/partial_mock.rb', line 234 def flexmock_find_expectation(*args, **kw, &block) @mock.flexmock_find_expectation(*args, **kw, &block) end |
#flexmock_get ⇒ Object
Get the mock object for the partial mock.
121 122 123 |
# File 'lib/flexmock/partial_mock.rb', line 121 def flexmock_get @mock end |
#flexmock_invoke_original(method, args, kw, block) ⇒ Object
Invoke the original definition of method on the object supported by the stub.
346 347 348 349 350 351 352 |
# File 'lib/flexmock/partial_mock.rb', line 346 def flexmock_invoke_original(method, args, kw, block) if (original_method = find_original_method(method)) original_method.call(*args, **kw, &block) else @obj.__send__(:method_missing, method, *args, **kw, &block) end end |
#flexmock_plain_new_method?(m) ⇒ Boolean
209 210 211 |
# File 'lib/flexmock/partial_mock.rb', line 209 def flexmock_plain_new_method?(m) m.name == :new && m.owner == Class end |
#flexmock_received?(*args, **kw) ⇒ Boolean
Forward to the mock
384 385 386 |
# File 'lib/flexmock/partial_mock.rb', line 384 def flexmock_received?(*args, **kw) @mock.flexmock_received?(*args, **kw) end |
#flexmock_teardown ⇒ Object
Remove all traces of the mocking framework from the existing object.
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
# File 'lib/flexmock/partial_mock.rb', line 361 def flexmock_teardown if ! detached? initialize_stub_remove proxy_module_eval do methods = instance_methods(false).to_a methods.each do |m| remove_method m end end if @obj.instance_variable_defined?(:@flexmock_proxy) && (box = @obj.instance_variable_get(:@flexmock_proxy)) box.pop end @obj = nil end end |
#flexmock_verify ⇒ Object
Verify that the mock has been properly called. After verification, detach the mocking infrastructure from the existing object.
356 357 358 |
# File 'lib/flexmock/partial_mock.rb', line 356 def flexmock_verify @mock.flexmock_verify end |
#has_original_method?(m) ⇒ Boolean
Whether the given method’s original definition has been stored
199 200 201 |
# File 'lib/flexmock/partial_mock.rb', line 199 def has_original_method?(m) find_original_method(m) end |
#has_proxied_method?(m) ⇒ Boolean
Whether the given method is already being proxied
204 205 206 207 |
# File 'lib/flexmock/partial_mock.rb', line 204 def has_proxied_method?(m) @proxy_definition_module && @proxy_definition_module.method_defined?(m) end |
#initialize_stub(recorder, expectations_block) ⇒ Object
Stubs the #initialize method on a class
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/flexmock/partial_mock.rb', line 289 def initialize_stub(recorder, expectations_block) if !@initialize_override expectation_blocks = @initialize_expectation_blocks = Array.new expectation_recorders = @initialize_expectation_recorders = Array.new @initialize_override = Module.new do define_method :initialize do |*args, **kw, &block| if self.class.respond_to?(:__flexmock_proxy) && (mock = self.class.__flexmock_proxy) container = mock.flexmock_container mock = container.flexmock(self) expectation_blocks.each do |b| b.call(mock) end expectation_recorders.each do |r| r.apply(mock) end end super(*args, **kw, &block) end end override = @initialize_override @obj.class_eval { prepend override } end if expectations_block @initialize_expectation_blocks << expectations_block end @initialize_expectation_recorders << recorder end |
#initialize_stub? ⇒ Boolean
317 318 319 |
# File 'lib/flexmock/partial_mock.rb', line 317 def initialize_stub? !!@initialize_override end |
#initialize_stub_remove ⇒ Object
321 322 323 324 325 326 |
# File 'lib/flexmock/partial_mock.rb', line 321 def initialize_stub_remove if initialize_stub? @initialize_expectation_blocks.clear @initialize_expectation_recorders.clear end end |
#invoke_original(m, *args, **kw, &block) ⇒ Object
Invoke the original of a mocked method
Usually called in a #and_return statement
164 165 166 |
# File 'lib/flexmock/partial_mock.rb', line 164 def invoke_original(m, *args, **kw, &block) flexmock_invoke_original(m, args, kw, block) end |
#new_instances(*allocators, &block) ⇒ Object
:call-seq:
new_instances.should_receive(...)
new_instances { |instance| instance.should_receive(...) }
new_instances is a short cut method for overriding the behavior of any new instances created via a mocked class object.
By default, new_instances will mock the behaviour of the :new method. If you wish to mock a different set of class methods, just pass a list of symbols to as arguments. (previous versions also mocked :allocate by default. If you need :allocate to be mocked, just request it explicitly).
For example, to stub only objects created by :make (and not :new), use:
flexmock(ClassName).new_instances(:make).should_receive(...)
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'lib/flexmock/partial_mock.rb', line 267 def new_instances(*allocators, &block) fail ArgumentError, "new_instances requires a Class to stub" unless Class === @obj location = caller allocators = [:initialize] if allocators.empty? expectation_recorder = ExpectationRecorder.new if allocators.delete(:initialize) initialize_stub(expectation_recorder, block) end allocators.each do |allocate_method| flexmock_define_expectation(location, allocate_method).and_return { |*args, **kw| create_new_mocked_object( allocate_method, args, kw, expectation_recorder, block) } end expectation_recorder end |
#original_method(m) ⇒ Object
Whether the given method’s original definition has been stored
191 192 193 194 195 196 |
# File 'lib/flexmock/partial_mock.rb', line 191 def original_method(m) unless (m = find_original_method(m)) raise ArgumentError, "no original method for #{m}" end m end |
#pop_flexmock_container ⇒ Object
129 130 131 |
# File 'lib/flexmock/partial_mock.rb', line 129 def pop_flexmock_container @mock.pop_flexmock_container end |
#push_flexmock_container(container) ⇒ Object
125 126 127 |
# File 'lib/flexmock/partial_mock.rb', line 125 def push_flexmock_container(container) @mock.push_flexmock_container(container) end |
#should_expect(*args) {|Recorder.new(self)| ... } ⇒ Object
157 158 159 |
# File 'lib/flexmock/partial_mock.rb', line 157 def should_expect(*args) yield Recorder.new(self) end |
#should_receive(*args, **kw) ⇒ Object
:call-seq:
should_receive(:method_name)
should_receive(:method1, method2, ...)
should_receive(:meth1 => result1, :meth2 => result2, ...)
Declare that the partial mock should receive a message with the given name.
If more than one method name is given, then the mock object should expect to receive all the listed melthods. If a hash of method name/value pairs is given, then the each method will return the associated result. Any expectations applied to the result of should_receive
will be applied to all the methods defined in the argument list.
An expectation object for the method name is returned as the result of this method. Further expectation constraints can be added by chaining to the result.
See Expectation for a list of declarators that can be used.
153 154 155 |
# File 'lib/flexmock/partial_mock.rb', line 153 def should_receive(*args, **kw) flexmock_define_expectation(caller, *args, **kw) end |