Mocha Release 0.9.1

Posted by James Mead Sat, 30 Aug 2008 16:48:00 GMT

Release Notes

  • Fixed bug #21465 – expects & stubs should support method names as strings (as well as symbols) or fail fast. Convert all expectation method names to a symbol in case they were supplied as a string.
  • By removing Mock#unexpected_method_called we reduce the number of methods vulnerable to the problem that surfaced in bug #21563.
  • Fix bug #21563 – stubbing ‘verified?’ method is unsafe. Instance method names on the Mock class should be more obscure.
  • Performance improvement. StubbaExampleTest goes twice as fast on my local machine.
  • Added primitive performance test to default rake task.
  • Fix format of case statements which don’t work in Ruby 1.9 and make others consistent.
  • There is no point in running (potentially expensive) checks if configuration is set to allow such checks to fail. This is a relatively quick fix in response to Chris McGrath’s performance problems.
  • Fix for bug #21161 – ‘uninitialized constant Deprecation in stubba.rb’.
  • It’s more readable to talk about ‘once’ and ‘twice’ rather than ‘1 time’ and ‘2 times’.
  • Fix bug #20883 – never should raise when called to prevent follow up errors. Fail fast when there are no matching invokable expectations and handle the stub_everything case sensibly. This might not be entirely backwards compatible, but I think the benefits outweigh the risks. The most likely change is that a test that was already failing will now fail faster, which doesn’t seem so awful.

Posted in  | Tags , , , , ,  | no comments

Mocha 0.9 Released

Posted by James Mead Tue, 24 Jun 2008 19:14:00 GMT

There’s been quite a bit of work going on in Mocha over recent months, but a release is long overdue. The API is now pretty stable and so this release jumps from version 0.5 to 0.9. Much of the work has been refactoring Mocha’s internals to support new features and make the code more maintainable.

Before attempting the refactoring, extensive acceptance tests were added. One of the benefits of this is that it should now be easier to write new acceptance tests if you want to suggest new features or illustrate a bug ;-)

Here’s a quick summary of the changes in the release. I’ll try to post some code examples here in the near future.

Ordering constraints

Based on the JMock constraints with the same names…

Configurable warnings or errors

  • When a method on a non-public method is stubbed
  • When a method on a non-existent method is stubbed
  • When a method on a non-mock object is stubbed (partial mocking)
  • When a method is stubbed unnecessarily (i.e. the stubbed method is not called during the test)

See Configuration for more details.

Improved error messages

  • A more readable and complete list of unsatisfied expectations, satisfied expectations and state machines.
  • Display more sensible failure message for any_instance expectations.

Parameter matchers

  • New to this release: optionally (allows matching of optional parameters if available), yaml_equivalent (allows matching of YAML that represents the specified object), responds_with (tests the quack not the duck).
  • Nesting of matchers is now supported.

Syntax shortcut

An optional block can be passed into the Standalone#mock method. The block is evaluated in the context of the new mock instance and can be used as a shortcut to set up expectations.

Ruby & Rails compatibility

Tested with Ruby 1.8.4, 1.8.5, 1.8.6 & 1.9. All related bugs and warnings believed to be fixed.

Tested with Rails 1.2.3 & Rails 2.1.0.

Deprecation

There is no longer any need to have a “require ‘stubba’” statement in your code. A deprecation warning has been added to this effect, because the file will be removed in a future release.

Bug fixes

Posted in  | Tags , , , , , ,  | no comments

Mocha 0.5 released

Posted by James Mead Fri, 08 Jun 2007 15:46:00 GMT

  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.

Posted in  | Tags , , , , ,  | 1 comment

Mocha 0.4 released

Posted by James Mead Mon, 22 Jan 2007 12:28:00 GMT

So I finally got round to releasing a new version of Mocha. Much of the functionality has been available for some time if you’ve been using the Rails plugin based on subversion HEAD, but now you can get it in all in a gem (or other package). The most recent changes centre around allowing mocking of Object instance methods.

Release notes…

  • Allow naming of mocks (patch from Chris Roos).
  • Specify multiple return values for consecutive calls.
  • Improved consistency of expectation error messages.
  • Allow mocking of Object instance methods e.g. kind_of?, type.
  • Provide aliased versions of #expects and #stubs to allow mocking of these methods.
  • Added at_least, at_most, at_most_once methods to expectation.
  • Allow expects and stubs to take a hash of method and return values.
  • Eliminate warning: “instance variable @yield not initialized” (patch from Xavier Shay).
  • Restore instance methods on partial mocks (patch from Chris Roos).
  • Allow stubbing of a method with non-word chars in its name (patch from Paul Battley).
  • Removed coupling to Test::Unit.
  • Allow specified exception instance to be raised (patch from Chris Roos).
  • Make mock object_id appear in hex like normal Ruby inspect (patch from Paul Battley).
  • Fix path to object.rb in rdoc rake task (patch from Tomas Pospisek).
  • Reverse order in which expectations are matched, so that last expectation is matched first. This allows e.g. a call to #stubs to be effectively overridden by a call to #expects (patch from Tobias Lutke).
  • Stubba & SmartTestCase modules incorporated into Mocha module so only need to require ‘mocha’ – no longer need to require ‘stubba’.
  • AutoMocha removed.

Thanks to all who contributed.

Enjoy :-)

Posted in  | Tags , , , , ,  | no comments

Mocha 0.3 released with Rails plugin

Posted by James Mead Thu, 24 Aug 2006 17:59:00 GMT

A new version of the Mocha mocking and stubbing library developed at Reevoo has been released.

There is now a Ruby on Rails plugin which can be installed like this…

  $ script/plugin install svn://rubyforge.org/var/svn/mocha/trunk

Here are the release notes…

  • Rails plugin.
  • Auto-verify for all expectations, including those on concrete classes.
  • Include each expectation verification in the test result assertion count.
  • Filter out noise from assertion backtraces.
  • Point assertion backtrace to line where failing expectation was created.
  • New yields method for expectations.
  • Create stubs which stub all method calls.
  • Mocks now respond_to? expected methods.

Thanks for patches from Chris.

Enjoy!

Posted in  | Tags , , , , , , , , , , ,  | 14 comments

Mocha 0.2 released

Posted by James Mead Fri, 11 Aug 2006 11:57:00 GMT

I’ve just released a new version of the Ruby mocking and stubbing library, Mocha, that I first mentioned a while ago. Here are the release notes:

  • Small change to SetupAndTeardown#teardown_stubs suggested by Luke Redpath to allow use of Stubba with RSpec.
  • Reorganized directory structure and extracted addition of setup and teardown methods into SmartTestCase mini-library.
  • Addition of auto-verify for Mocha (but not Stubba). This means there is more significance in the choice of expects or stubs in that any expects on a mock will automatically get verified.

So instead of…

  wotsit = Mocha.new
  wotsit.expects(:thingummy).with(5).returns(10)
  doobrey = Doobrey.new(wotsit)
  doobrey.hoojamaflip
  wotsit.verify

you need to do…

  wotsit = mock()
  wotsit.expects(:thingummy).with(5).returns(10)
  doobrey = Doobrey.new(wotsit)
  doobrey.hoojamaflip
  # no need to verify

There are also shortcuts as follows…

instead of…

  wotsit = Mocha.new
  wotsit.expects(:thingummy).returns(10)
  wotsit.expects(:summat).returns(25)

you can have…

  wotsit = mock(:thingummy => 5, :summat => 25)

and instead of…

  wotsit = Mocha.new
  wotsit.stubs(:thingummy).returns(10)
  wotsit.stubs(:summat).returns(25)

you can have…

  wotsit = stub(:thingummy => 5, :summat => 25)

Posted in  | Tags , , , , , , , , ,  | 4 comments

Mocking and stubbing in Ruby

Posted by James Mead Sun, 16 Jul 2006 17:32:00 GMT

Over the last few months, I’ve been working on Mocha which is a Ruby mocking library with a syntax like that of JMock and SchMock. And I’ve finally got round to putting it up on RubyForge.

Mocha comes in three parts:

  • Mocha – traditional mock objects with expectations and verification
  • Stubba – allows mocking and stubbing of methods on real (non-mock) classes
  • AutoMocha – magically provides mocks in the place of undefined classes

Mocha and Stubba have been created by amalgamating a number of techniques developed by me and my Reevoo colleagues (Ben, Chris and Paul) into a common syntax. Both Mocha and Stubba are in use on real-world Rails projects.

AutoMocha is more experimental and is at an earlier stage of development. It’s an attempt to make it easier to write true unit tests (i.e. tests with no external dependencies).

You can find examples in the RDoc README and in the acceptance tests.

Posted in  | Tags , , , , ,  | no comments