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
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
-
#method_definitions ⇒ Object
readonly
Returns the value of attribute method_definitions.
-
#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.
-
#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(…) }.
- #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.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/flexmock/partial_mock.rb', line 105 def initialize(obj, mock, safe_mode, parent: nil) @obj = obj @mock = mock @proxy_definition_module = nil @initialize_override = nil if parent @method_definitions = parent.method_definitions.dup else @method_definitions = {} end 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
#method_definitions ⇒ Object (readonly)
Returns the value of attribute method_definitions.
102 103 104 |
# File 'lib/flexmock/partial_mock.rb', line 102 def method_definitions @method_definitions end |
#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
209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/flexmock/partial_mock.rb', line 209 def add_mock_method(method_name) stow_existing_definition(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 |
#flexmock_based_on(*args) ⇒ Object
Forward the based on request.
380 381 382 |
# File 'lib/flexmock/partial_mock.rb', line 380 def flexmock_based_on(*args) @mock.flexmock_based_on(*args) end |
#flexmock_calls ⇒ Object
Forward to the mock
365 366 367 |
# File 'lib/flexmock/partial_mock.rb', line 365 def flexmock_calls @mock.flexmock_calls end |
#flexmock_container ⇒ Object
Forward to the mock’s container.
355 356 357 |
# File 'lib/flexmock/partial_mock.rb', line 355 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.
371 372 |
# File 'lib/flexmock/partial_mock.rb', line 371 def flexmock_container=(container) end |
#flexmock_define_expectation(location, *args) ⇒ Object
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/flexmock/partial_mock.rb', line 189 def flexmock_define_expectation(location, *args) EXP_BUILDER.parse_should_args(self, args) do |method_name| if !has_proxied_method?(method_name) && !has_original_method?(method_name) hide_existing_method(method_name) end ex = @mock.flexmock_define_expectation(location, method_name) if FlexMock.partials_verify_signatures if existing_method = @method_definitions[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.
375 376 377 |
# File 'lib/flexmock/partial_mock.rb', line 375 def flexmock_expectations_for(method_name) @mock.flexmock_expectations_for(method_name) end |
#flexmock_find_expectation(*args) ⇒ Object
205 206 207 |
# File 'lib/flexmock/partial_mock.rb', line 205 def flexmock_find_expectation(*args) @mock.flexmock_find_expectation(*args) end |
#flexmock_get ⇒ Object
Get the mock object for the partial mock.
128 129 130 |
# File 'lib/flexmock/partial_mock.rb', line 128 def flexmock_get @mock end |
#flexmock_invoke_original(method, args) ⇒ Object
Invoke the original definition of method on the object supported by the stub.
318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/flexmock/partial_mock.rb', line 318 def flexmock_invoke_original(method, args) if original_method = @method_definitions[method] if Proc === args.last block = args.last args = args[0..-2] end original_method.bind(@obj).call(*args, &block) else @obj.__send__(:method_missing, method, *args, &block) end end |
#flexmock_received?(*args) ⇒ Boolean
Forward to the mock
360 361 362 |
# File 'lib/flexmock/partial_mock.rb', line 360 def flexmock_received?(*args) @mock.flexmock_received?(*args) end |
#flexmock_teardown ⇒ Object
Remove all traces of the mocking framework from the existing object.
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
# File 'lib/flexmock/partial_mock.rb', line 337 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.
332 333 334 |
# File 'lib/flexmock/partial_mock.rb', line 332 def flexmock_verify @mock.flexmock_verify end |
#has_original_method?(m) ⇒ Boolean
Whether the given method’s original definition has been stored
179 180 181 |
# File 'lib/flexmock/partial_mock.rb', line 179 def has_original_method?(m) @method_definitions.has_key?(m) end |
#has_proxied_method?(m) ⇒ Boolean
Whether the given method is already being proxied
184 185 186 187 |
# File 'lib/flexmock/partial_mock.rb', line 184 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
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/flexmock/partial_mock.rb', line 261 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
289 290 291 |
# File 'lib/flexmock/partial_mock.rb', line 289 def initialize_stub? !!@initialize_override end |
#initialize_stub_remove ⇒ Object
293 294 295 296 297 298 |
# File 'lib/flexmock/partial_mock.rb', line 293 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
171 172 173 174 175 176 |
# File 'lib/flexmock/partial_mock.rb', line 171 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(...)
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/flexmock/partial_mock.rb', line 239 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 |
#pop_flexmock_container ⇒ Object
136 137 138 |
# File 'lib/flexmock/partial_mock.rb', line 136 def pop_flexmock_container @mock.pop_flexmock_container end |
#push_flexmock_container(container) ⇒ Object
132 133 134 |
# File 'lib/flexmock/partial_mock.rb', line 132 def push_flexmock_container(container) @mock.push_flexmock_container(container) end |
#should_expect(*args) {|Recorder.new(self)| ... } ⇒ Object
164 165 166 |
# File 'lib/flexmock/partial_mock.rb', line 164 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.
160 161 162 |
# File 'lib/flexmock/partial_mock.rb', line 160 def should_receive(*args) flexmock_define_expectation(caller, *args) end |