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) ⇒ Object
-
#flexmock_expectations_for(method_name) ⇒ Object
Forward the request for the expectation director to the mock.
- #flexmock_find_expectation(*args) ⇒ Object
-
#flexmock_get ⇒ Object
Get the mock object for the partial mock.
-
#flexmock_invoke_original(method, args) ⇒ Object
Invoke the original definition of method on the object supported by the stub.
-
#flexmock_received?(*args) ⇒ 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, &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) ⇒ 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
226 227 228 229 230 231 232 233 234 235 |
# File 'lib/flexmock/partial_mock.rb', line 226 def add_mock_method(method_name) proxy_module_eval do define_method(method_name) { |*args, &block| proxy = __flexmock_proxy or fail "Missing FlexMock proxy " + "(for method_name=#{method_name.inspect}, self=\#{self})" proxy.send(method_name, *args, &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
172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/flexmock/partial_mock.rb', line 172 def find_original_method(m) it = @obj.method(m) 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.
396 397 398 |
# File 'lib/flexmock/partial_mock.rb', line 396 def flexmock_based_on(*args) @mock.flexmock_based_on(*args) end |
#flexmock_calls ⇒ Object
Forward to the mock
381 382 383 |
# File 'lib/flexmock/partial_mock.rb', line 381 def flexmock_calls @mock.flexmock_calls end |
#flexmock_container ⇒ Object
Forward to the mock’s container.
371 372 373 |
# File 'lib/flexmock/partial_mock.rb', line 371 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.
387 388 |
# File 'lib/flexmock/partial_mock.rb', line 387 def flexmock_container=(container) end |
#flexmock_define_expectation(location, *args) ⇒ Object
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'lib/flexmock/partial_mock.rb', line 206 def flexmock_define_expectation(location, *args) EXP_BUILDER.parse_should_args(self, args) 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)) ex.with_signature_matching(existing_method) end end ex.mock = self ex end end |
#flexmock_expectations_for(method_name) ⇒ Object
Forward the request for the expectation director to the mock.
391 392 393 |
# File 'lib/flexmock/partial_mock.rb', line 391 def flexmock_expectations_for(method_name) @mock.flexmock_expectations_for(method_name) end |
#flexmock_find_expectation(*args) ⇒ Object
222 223 224 |
# File 'lib/flexmock/partial_mock.rb', line 222 def flexmock_find_expectation(*args) @mock.flexmock_find_expectation(*args) 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) ⇒ Object
Invoke the original definition of method on the object supported by the stub.
334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/flexmock/partial_mock.rb', line 334 def flexmock_invoke_original(method, args) if (original_method = find_original_method(method)) if Proc === args.last block = args.last args = args[0..-2] end original_method.call(*args, &block) else @obj.__send__(:method_missing, method, *args, &block) end end |
#flexmock_received?(*args) ⇒ Boolean
Forward to the mock
376 377 378 |
# File 'lib/flexmock/partial_mock.rb', line 376 def flexmock_received?(*args) @mock.flexmock_received?(*args) end |
#flexmock_teardown ⇒ Object
Remove all traces of the mocking framework from the existing object.
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
# File 'lib/flexmock/partial_mock.rb', line 353 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.
348 349 350 |
# File 'lib/flexmock/partial_mock.rb', line 348 def flexmock_verify @mock.flexmock_verify end |
#has_original_method?(m) ⇒ Boolean
Whether the given method’s original definition has been stored
196 197 198 |
# File 'lib/flexmock/partial_mock.rb', line 196 def has_original_method?(m) find_original_method(m) end |
#has_proxied_method?(m) ⇒ Boolean
Whether the given method is already being proxied
201 202 203 204 |
# File 'lib/flexmock/partial_mock.rb', line 201 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
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/flexmock/partial_mock.rb', line 277 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, &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, &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
305 306 307 |
# File 'lib/flexmock/partial_mock.rb', line 305 def initialize_stub? !!@initialize_override end |
#initialize_stub_remove ⇒ Object
309 310 311 312 313 314 |
# File 'lib/flexmock/partial_mock.rb', line 309 def initialize_stub_remove if initialize_stub? @initialize_expectation_blocks.clear @initialize_expectation_recorders.clear end end |
#invoke_original(m, *args, &block) ⇒ Object
Invoke the original of a mocked method
Usually called in a #and_return statement
164 165 166 167 168 169 |
# File 'lib/flexmock/partial_mock.rb', line 164 def invoke_original(m, *args, &block) if block args << block end flexmock_invoke_original(m, args) 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(...)
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/flexmock/partial_mock.rb', line 255 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| create_new_mocked_object( allocate_method, args, expectation_recorder, block) } end expectation_recorder end |
#original_method(m) ⇒ Object
Whether the given method’s original definition has been stored
188 189 190 191 192 193 |
# File 'lib/flexmock/partial_mock.rb', line 188 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) ⇒ 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) flexmock_define_expectation(caller, *args) end |