Mocha 0.5 released

sudo gem install mocha

or download one of the latest packages from rubyforge.

Parameter Matchers

I’ve added a few Hamcrest-style parameter matchers which are designed to be used inside Expectation#with. The following matchers are currently available: anything(), includes(), has_key(), has_value(), has_entry(), all_of() & any_of(). More to follow soon. The idea is eventually to get rid of the nasty parameter_block option on Expectation#with.

object = mock()
object.expects(:method).with(has_key('key_1'))
object.method('key_1' => 1, 'key_2' => 2)
# no verification error raised
object = mock()
object.expects(:method).with(has_key('key_1'))
object.method('key_2' => 2)
# verification error raised, because method was not called with Hash containing key: 'key_1'

Values Returned and Exceptions Raised on Consecutive Invocations

Allow multiple calls to Expectation#returns and Expectation#raises to build up a sequence of responses to invocations on the mock. Added syntactic sugar method Expectation#then to allow more readable expectations.

object = mock()
object.stubs(:method).returns(1, 2).then.raises(Exception).then.returns(4)
object.method # => 1
object.method # => 2
object.method # => raises exception of class Exception
object.method # => 4

Yields on Consecutive Invocations

Allow multiple calls to yields on single expectation to allow yield parameters to be specified for consecutive invocations.

object = mock()
object.stubs(:method).yields(1, 2).then.yields(3)
object.method { |*values| p values } # => [1, 2]
object.method { |*values| p values } # => [3]

Multiple Yields on Single Invocation

Added Expectation#multiple_yields to allow a mocked or stubbed method to yield multiple times for a single invocation.

object = mock()
object.stubs(:method).multiple_yields([1, 2], [3])
object.method { |*values| p values } # => [1, 2] # => [3]

Invocation Dispatch

Expectations were already being matched in reverse order i.e. the most recently defined one was being found first. This is still the case, but we now stop matching an expectation when its maximum number of expected invocations is reached. c.f. JMock v1. A stub will never stop matching by default. Hopefully this means we can soon get rid of the need to pass a Proc to Expectation#returns.

object = mock()
object.stubs(:method).returns(2)
object.expects(:method).once.returns(1)
object.method # => 1
object.method # => 2
object.method # => 2
# no verification error raised

This should still work…

Time.stubs(:now).returns(Time.parse('Mon Jan 01 00:00:00 UTC 2007'))
Time.now # => Mon Jan 01 00:00:00 UTC 2007
Time.stubs(:now).returns(Time.parse('Thu Feb 01 00:00:00 UTC 2007'))
Time.now # => Thu Feb 01 00:00:00 UTC 2007

Acknowledgements

Thanks to David Chelimsky, Dan North, Jay Fields, Kevin Clark, Frederick Cheung, James Moore, Brian Helmkamp, Ben Griffiths, Chris Roos & Paul Battley for their input. Apologies to anybody I forgot to mention.