I’ve been writing a ‘toy’ Rails application by way of a learning excerise (read: attempting to de-hype Rails, in my own mind if nowhere else). Whilst investigating at the tool offerings (or lack thereof) I started looking at the mocking tools available. Coming from a perspective as a frequent JMock user I was hoping to find something similar.
<!-more->

RubyMock

Originally written way back in 2001 by Nat Pryce (who also wrote Java’s DynaMock and JMock tools) RubyMock was the first mocking tool for Ruby. It was written to integrate with RubyTest which has now been superceeded by TestUnit – now built in to the core Ruby distribution.

Test::Unit::Mock

Test::Unit::Mock (try saying that three times fast) is a reimplementation of RubyMock, only this time using the newer TestUnit. For someone used to the nice, readable JMock expectations, RubyMock is far from pretty. This example shows setting the expectation for a mock to return a value when the do_stuff method is called:
(C)

(C)<textarea name="code" class="ruby" cols="60" rows="10">
mock_object.setReturnValues( :do_stuff => [
“Mocked Return”
] )
</textarea>

Personally, I dont find it as readable as JMock:

mock_object.
  expects(once()).
  method("do_stuff").
  will(returnValue("Mocked Return"))

That seems about as sophisticated as the mocks get – you can specify call order (something I’ve never needed to do in JMock) but I couldn’t see any way to verify expected arguments made in method calls, apart from adding your own mocking methods.

FlexMock

FlexMock seems a little more recent than either of the above, and I prefer it’s wording if nothing else:

mock_object = FlexMock.new
mock_object.mock_handle(:do_stuff) {
  "Mocked Return"
}

The only way to assert arguments being passed to the mock is to place assertions within the block itself – compare this with JMock:

mock_object.expects(once()).
  method("do_stuff").
  with(eq(someParam)).
  will(returnValue("Mocked Return"))

A JMock port for Ruby?

Much of JMock is focused at making readable expectations – I certainly find them to be more self-explanatory than the Ruby equivilents shown above. There is a certain amount of extra language required for the expectations to work in Java which wouldn’t need to be done for Ruby – for example you could do away with the need to cast the mock’s proxy, so instead or:

MyObject object =
  new MyObject((Dependency)mockDependency.proxy());

You could have:

MyObject object = MyObject.new(mockDependency.proxy())

Even better, you could do away with the need for the proxy altogether due to the nature of Ruby’s typing:

MyObject object = MyObject.new(mockDependency)

Likewise I think there is scope to simplify the way you define expectations in JMock. Instead of:

Mock mockObject = new Mock(ClazzToMock.class);
mockObject.expects(once()).
  method("someOperation").
  with(eq(arg1), eq(arg2)).
  will(returnValue(someReturn));

Compared to:

mockObject = Mock.new(ClazzToMock)
mockObject.expects(:someOperation).
  with(arg1, arg2).
  willReturn(someReturn)

Implementing such a mocking tool would be simple – much of the work in JMock covers the creation and use of dynamic proxies, which are a breeze to implement in Ruby. Whilst writing my tool I’ve already created the bits that should make this possible, the question is whether or not I can be bothered to finish it off. In the meantime I’m going to take a look at the Python version of JMock, PMock for inspiration.

Advertisements