Class: Hardmock::Expectation
- Includes:
- Utils
- Defined in:
- lib/hardmock/expectation.rb
Instance Attribute Summary collapse
-
#block_value ⇒ Object
readonly
Returns the value of attribute block_value.
Instance Method Summary collapse
-
#apply_method_call(mock, mname, args, block) ⇒ Object
:nodoc:.
-
#initialize(options) ⇒ Expectation
constructor
:nodoc:.
-
#raises(err = nil) ⇒ Object
Rig an expected method to raise an exception when the mock is invoked.
-
#returns(val) ⇒ Object
(also: #and_return)
Set the return value for an expected method call.
-
#to_s ⇒ Object
:nodoc:.
-
#trigger(*block_arguments) ⇒ Object
Convenience method: assumes
block_value
is set, and is set to a Proc (or anything that responds to ‘call’). -
#with(*args) ⇒ Object
Set the arguments for an expected method call.
-
#yields(*items) ⇒ Object
Used when an expected method accepts a block at runtime.
Methods included from Utils
Constructor Details
#initialize(options) ⇒ Expectation
:nodoc:
8 9 10 |
# File 'lib/hardmock/expectation.rb', line 8 def initialize() #:nodoc: = end |
Instance Attribute Details
#block_value ⇒ Object (readonly)
Returns the value of attribute block_value.
6 7 8 |
# File 'lib/hardmock/expectation.rb', line 6 def block_value @block_value end |
Instance Method Details
#apply_method_call(mock, mname, args, block) ⇒ Object
:nodoc:
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/hardmock/expectation.rb', line 12 def apply_method_call(mock,mname,args,block) #:nodoc: unless [:mock].equal?(mock) raise anger("Wrong object", mock,mname,args) end unless [:method] == mname raise anger("Wrong method",mock,mname,args) end # Tester-defined block to invoke at method-call-time: expectation_block = [:block] expected_args = [:arguments] # if we have a block, we can skip the argument check if none were specified unless (expected_args.nil? || expected_args.empty?) && expectation_block && ![:suppress_arguments_to_block] unless expected_args == args raise anger("Wrong arguments",mock,mname,args) end end relayed_args = args.dup if block if expectation_block.nil? # Can't handle a runtime block without an expectation block raise ExpectationError.new("Unexpected block provided to #{to_s}") else # Runtime blocks are passed as final argument to the expectation block unless [:suppress_arguments_to_block] relayed_args << block else # Arguments suppressed; send only the block relayed_args = [block] end end end # Run the expectation block: @block_value = expectation_block.call(*relayed_args) if expectation_block raise [:raises] unless [:raises].nil? return_value = [:returns] if return_value.nil? return @block_value else return return_value end end |
#raises(err = nil) ⇒ Object
Rig an expected method to raise an exception when the mock is invoked.
Eg,
@cash_machine.expects.withdraw(20,:dollars).raises "Insufficient funds"
The argument can be:
-
an Exception – will be used directly
-
a String – will be used as the message for a RuntimeError
-
nothing – RuntimeError.new(“An Error”) will be raised
86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/hardmock/expectation.rb', line 86 def raises(err=nil) case err when Exception [:raises] = err when String [:raises] = RuntimeError.new(err) else [:raises] = RuntimeError.new("An Error") end self end |
#returns(val) ⇒ Object Also known as: and_return
Set the return value for an expected method call. Eg,
@cash_machine.expects.withdraw(20,:dollars).returns(20.00)
63 64 65 66 |
# File 'lib/hardmock/expectation.rb', line 63 def returns(val) [:returns] = val self end |
#to_s ⇒ Object
:nodoc:
220 221 222 |
# File 'lib/hardmock/expectation.rb', line 220 def to_s # :nodoc: format_method_call_string([:mock],[:method],[:arguments]) end |
#trigger(*block_arguments) ⇒ Object
Convenience method: assumes block_value
is set, and is set to a Proc (or anything that responds to ‘call’)
light_event = @traffic_light.trap.subscribe(:light_changes)
# This code will meet the expectation:
@traffic_light.subscribe :light_changes do |color|
puts color
end
The color-handling block is now stored in light_event.block_value
The block can be invoked like this:
light_event.trigger :red
See Mock#trap and Mock#expects for information on using expectation objects after they are set.
117 118 119 120 121 122 123 124 125 |
# File 'lib/hardmock/expectation.rb', line 117 def trigger(*block_arguments) unless block_value raise ExpectationError.new("No block value is currently set for expectation #{to_s}") end unless block_value.respond_to?(:call) raise ExpectationError.new("Can't apply trigger to #{block_value} for expectation #{to_s}") end block_value.call *block_arguments end |
#with(*args) ⇒ Object
Set the arguments for an expected method call. Eg,
@cash_machine.expects.deposit.with(20, "dollars").returns(:balance => "20")
72 73 74 75 |
# File 'lib/hardmock/expectation.rb', line 72 def with(*args) [:arguments] = args self end |
#yields(*items) ⇒ Object
Used when an expected method accepts a block at runtime.
When the expected method is invoked, the block passed to that method will be invoked as well.
NOTE: ExpectationError will be thrown upon running the expected method if the arguments you set up in yields
do not properly match up with the actual block that ends up getting passed.
Examples
Single invocation: The block passed to lock_down
gets invoked once with no arguments:
@safe_zone.expects.lock_down.yields
# (works on code that looks like:)
@safe_zone.lock_down do
# ... this block invoked once
end
Multi-parameter blocks: The block passed to each_item
gets invoked twice, with :item1
the first time, and with :item2
the second time:
@fruit_basket.expects.each_with_index.yields [:apple,1], [:orange,2]
# (works on code that looks like:)
@fruit_basket.each_with_index do |fruit,index|
# ... this block invoked with fruit=:apple, index=1,
# ... and then with fruit=:orange, index=2
end
Arrays can be passed as arguments too… if the block takes a single argument and you want to pass a series of arrays into it, that will work as well:
@list_provider.expects.each_list.yields [1,2,3], [4,5,6]
# (works on code that looks like:)
@list_provider.each_list do |list|
# ... list is [1,2,3] the first time
# ... list is [4,5,6] the second time
end
Return value: You can set the return value for the method that accepts the block like so:
@cruncher.expects.do_things.yields(:bean1,:bean2).returns("The Results")
Raising errors: You can set the raised exception for the method that accepts the block. NOTE: the error will be raised after the block has been invoked.
# :bean1 and :bean2 will be passed to the block, then an error is raised:
@cruncher.expects.do_things.yields(:bean1,:bean2).raises("Too crunchy")
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/hardmock/expectation.rb', line 182 def yields(*items) [:suppress_arguments_to_block] = true if items.empty? # Yield once [:block] = lambda do |block| if block.arity != 0 and block.arity != -1 raise ExpectationError.new("The given block was expected to have no parameter count; instead, got #{block.arity} to <#{to_s}>") end block.call end else # Yield one or more specific items [:block] = lambda do |block| items.each do |item| if item.kind_of?(Array) if block.arity == item.size # Unfold the array into the block's arguments: block.call *item elsif block.arity == 1 # Just pass the array in block.call item else # Size mismatch raise ExpectationError.new("Can't pass #{item.inspect} to block with arity #{block.arity} to <#{to_s}>") end else if block.arity != 1 # Size mismatch raise ExpectationError.new("Can't pass #{item.inspect} to block with arity #{block.arity} to <#{to_s}>") end block.call item end end end end self end |