Class: Hardmock::Mock
- Includes:
- MethodCleanout
- Defined in:
- lib/hardmock/mock.rb
Overview
Mock is used to set expectations in your test. Most of the time you’ll use #expects
to create expectations.
Aside from the scant few control methods (like expects
, trap
and _verify
) all calls made on a Mock instance will be immediately applied to the internal expectation mechanism.
-
If the method call was expected and all the parameters match properly, execution continues
-
If the expectation was configured with an expectation block, the block is invoked
-
If the expectation was set up to raise an error, the error is raised now
-
If the expectation was set up to return a value, it is returned
-
If the method call was not expected, or the parameter values are wrong, an ExpectationError is raised.
Constant Summary
Constants included from MethodCleanout
Hardmock::MethodCleanout::SACRED_METHODS
Instance Method Summary collapse
-
#_control ⇒ Object
:nodoc:.
-
#_name ⇒ Object
:nodoc:.
-
#_verify ⇒ Object
Verify that all expectations are fulfilled.
-
#expects(*args, &block) ⇒ Object
(also: #expect, #should_receive)
Begin declaring an expectation for this Mock.
-
#initialize(name, mock_control = nil) ⇒ Mock
constructor
Create a new Mock instance with a name and a MockControl to support it.
- #inspect ⇒ Object
-
#method_missing(mname, *args) ⇒ Object
:nodoc:.
-
#trap(*args) ⇒ Object
Special-case convenience: #trap sets up an expectation for a method that will take a block.
Methods included from MethodCleanout
Constructor Details
#initialize(name, mock_control = nil) ⇒ Mock
Create a new Mock instance with a name and a MockControl to support it. If not given, a MockControl is made implicitly for this Mock alone; this means expectations for this mock are not tied to other expectations in your test.
It’s not recommended to use a Mock directly; see Hardmock and Hardmock#create_mocks for the more wholistic approach.
24 25 26 27 28 |
# File 'lib/hardmock/mock.rb', line 24 def initialize(name, mock_control=nil) @name = name @control = mock_control || MockControl.new @expectation_builder = ExpectationBuilder.new end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(mname, *args) ⇒ Object
:nodoc:
153 154 155 156 157 |
# File 'lib/hardmock/mock.rb', line 153 def method_missing(mname,*args) #:nodoc: block = nil block = Proc.new if block_given? @control.apply_method_call(self,mname,args,block) end |
Instance Method Details
#_control ⇒ Object
:nodoc:
160 161 162 |
# File 'lib/hardmock/mock.rb', line 160 def _control #:nodoc: @control end |
#_name ⇒ Object
:nodoc:
164 165 166 |
# File 'lib/hardmock/mock.rb', line 164 def _name #:nodoc: @name end |
#_verify ⇒ Object
Verify that all expectations are fulfilled. NOTE: this method triggers validation on the control for this mock, so all Mocks that share the MockControl with this instance will be included in the verification.
Only use this method if you are managing your own Mocks and their controls.
Normal usage of Hardmock doesn’t require you to call this; let Hardmock#verify_mocks do it for you.
176 177 178 |
# File 'lib/hardmock/mock.rb', line 176 def _verify @control.verify end |
#expects(*args, &block) ⇒ Object Also known as: expect, should_receive
Begin declaring an expectation for this Mock.
Simple Examples
Expect the customer
to be queried for account
, and return "The Account"
:
@customer.expects.account.returns "The Account"
Expect the withdraw
method to be called, and raise an exception when it is (see Expectation#raises for more info):
@cash_machine.expects.withdraw(20,:dollars).raises("not enough money")
Expect customer
to have its user_name
set
@customer.expects.user_name = 'Big Boss'
Expect customer
to have its user_name
set, and raise a RuntimeException when that happens:
@customer.expects('user_name=', "Big Boss").raises "lost connection"
Expect evaluate
to be passed a block, and when that happens, pass a value to the block (see Expectation#yields for more info):
@cruncher.expects.evaluate.yields("some data").returns("some results")
Expectation Blocks
To do special handling of expected method calls when they occur, you may pass a block to your expectation, like:
@page_scraper.expects.handle_content do |address,request,status|
assert_not_nil address, "Can't abide nil addresses"
assert_equal "http-get", request.method, "Can only handle GET"
assert status > 200 and status < 300, status, "Failed status"
"Simulated results #{request.content.downcase}"
end
In this example, when page_scraper.handle_content
is called, its three arguments are passed to the expectation block and evaluated using the above assertions. The last value in the block will be used as the return value for handle_content
You may specify arguments to the expected method call, just like any normal expectation, and those arguments will be pre-validated before being passed to the expectation block. This is useful when you know all of the expected values but still need to do something programmatic.
If the method being invoked on the mock accepts a block, that block will be passed to your expectation block as the last (or only) argument. Eg, the convenience method yields
can be replaced with the more explicit:
@cruncher.expects.evaluate do |block|
block.call "some data"
"some results"
end
The result value of the expectation block becomes the return value for the expected method call. This can be overidden by using the returns
method:
@cruncher.expects.evaluate do |block|
block.call "some data"
"some results"
end.returns("the actual value")
Additionally, the resulting value of the expectation block is stored in the block_value
field on the expectation. If you’ve saved a reference to your expectation, you may retrieve the block value once the expectation has been met.
evaluation_event = @cruncher.expects.evaluate do |block|
block.call "some data"
"some results"
end.returns("the actual value")
result = @cruncher.evaluate do |input|
puts input # => 'some data'
end
# result is 'the actual value'
evaluation_event.block_value # => 'some results'
108 109 110 111 112 113 114 |
# File 'lib/hardmock/mock.rb', line 108 def expects(*args, &block) expector = Expector.new(self,@control,@expectation_builder) # If there are no args, we return the Expector return expector if args.empty? # If there ARE args, we set up the expectation right here and return it expector.send(args.shift.to_sym, *args, &block) end |
#inspect ⇒ Object
30 31 32 |
# File 'lib/hardmock/mock.rb', line 30 def inspect "<Mock #{@name}>" end |
#trap(*args) ⇒ Object
Special-case convenience: #trap sets up an expectation for a method that will take a block. That block, when sent to the expected method, will be trapped and stored in the expectation’s block_value
field. The Expectation#trigger method may then be used to invoke that block.
Like expects
, the trap
mechanism can be followed by raises
or returns
.
Unlike expects
, you may not use an expectation block with trap
. If the expected method takes arguments in addition to the block, they must be specified in the arguments to the trap
call itself.
Example
create_mocks :address_book, :editor_form
# Expect a subscription on the :person_added event for @address_book:
person_event = @address_book.trap.subscribe(:person_added)
# The runtime code would look like:
@address_book.subscribe :person_added do |person_name|
@editor_form.name = person_name
end
# At this point, the expectation for 'subscribe' is met and the
# block has been captured. But we're not done:
@editor_form.expects.name = "David"
# Now invoke the block we trapped earlier:
person_event.trigger "David"
verify_mocks
149 150 151 |
# File 'lib/hardmock/mock.rb', line 149 def trap(*args) Trapper.new(self,@control,ExpectationBuilder.new) end |