Yesterday we brought home our newest addition to the Moazeni household. Meet our new Great Dane. Brutus:

He’s been quite the handful, and boy is he scrappy. He does not have any qualms about showing off his puppy bark. His first encounter with Mocha he gave her a few tiny growls and barks and now she steers clear of him.

So if see this little Harlequin on the street, watch out. He’ll give you a piece of his mind. Just ask his chew toys and my socks.
Most ruby developers who use mock libraries are familiar with either Mocha or Flex Mock. However not many are familiar with the mock library that I use, Hardmock.
Hardmock takes mocking one step further to assert order between mocks, much like the Java mocking library EasyMock
class Person
def initialize(car, wallet)
@car = car
@wallet = wallet
end
def go_to_movies
@car.drive_to_movies
@wallet.pay_for_ticket("10.00")
@car.drive_home
end
end
...
# in tests
def setup
create_mocks :car_mock, :wallet_mock
@person = Person.new(@car_mock, @wallet_mock)
end
# This test will pass
def test_go_to_movies
@car_mock.expects.drive_to_movies
@wallet_mock.expects.pay_for_ticket("10.00")
@car_mock.expects.drive_home
@person.go_to_movies
end
# This test will fail since we
# drive home before we paid for the ticket
def test_go_to_movies_failure
@car_mock.expects.drive_to_movies
@car_mock.expects.drive_home
@wallet_mock.expects.pay_for_ticket("10.00")
@person.go_to_movies
end
Another one of my favorite perks of Hardmock is the open assertions of parameters. For the most part, parameters are expected to equal what is given in the initial assertions, however sometimes there’s complications on asserting the parameters given.
def test_allow_any_money_for_ticket
@car_mock.expects.drive_to_movies
@wallet_mock.expects.pay_for_ticket do | amount |
# this will be executed when "pay_for_ticket" is called on the mock
# Only allow dollar amounts
assert_match(/^\d+\.\d{2}$/, amount)
# of course the last value in this block
# with be returned from the mock to the caller
"the ticket"
end
@car_mock.expects.drive_home
@person.go_to_movies
end
Hardmock was written by the solid developers at Atomic Object
As a developer you face many situations where things will just not work, then you have a revelation that points to something so simple that you want to slap yourself.
I just had one today so profound I thought I’d share it with the public.
I wanted to have fun on my day off, but instead of going outside on the beautiful day, or doing some thing active like any sane person, I decided to play with FlexMock and Mocha.
I had my fun with FlexMock and was moving onto Mocha, when I encountered a strange yet irritating problem.
require "rubygems"
require "test/unit"
require "mocha"
require "others"
class OthersTest < Test::Unit::TestCase
def test_foo
person = mock("person")
end
end
I kept getting
E
Finished in 0.000419 seconds.
1) Error:
test_foo(OthersTest):
NoMethodError: undefined method `mock' for #<OthersTest:0x110b5c4>
So I went over my gems to make sure they were installed correctly. Even grabbed a sample test file and that resulted in the same error.
So I edited the mocha.rb in the gem lib directory and added one of my Yoda-like scientific debugging techniques
puts "in here"
Still having problems. So I tweaked the test case a little to
require "rubygems"
require "test/unit"
require_gem "mocha"
require "others"
Success! … if you ignore the Deprecation Warning from rubygems. Warning: require_gem is obsolete. Use gem instead. Being a perfectionist, that irked me.
Wondering how this gem could hate me in particular yet spare everyone else it’s wrath, I stepped back and noticed the forest for the trees. The test’s filename was mocha.rb. An innocuous file name from a sleepy eyed programmer at 8 a.m. in the morning. (More support that coders shouldn’t touch a keyboard before 10 a.m.)
The original require "mocha" was seeming to ignore the gem because it was named the same, and of course I plopped the sample file in the same directory as the uglified test, so it wouldn’t grab the gem.
Why do Dumb Moments always last at least one hour?
Previously I spoke about Hardmock, a mocking library. Most of the time I try to develop using Dependency Injection or at least keep instantiation of objects together. However, sometimes the real world kicks in and I can’t or don’t have time to refactor the code.
Enter Hardstub. This will replace the definition of a class with a mock. Again, I’m not promoting testing in this manner, but this may open possibilities that may have been previously discounted.
class Person
def initialize(car)
@car = car
@wallet = Wallet.new
end
def go_to_movies
@car.drive_to_movies
@wallet.pay_for_ticket("10.00")
@car.drive_home
end
end
class Wallet
# not fully implemented yet
end
...
# in tests
def setup
stub(Wallet)
create_mock :car_mock, :wallet_mock
end
def teardown
# this is needed
revert_stubs
end
def test_go_to_movies
Wallet.expects.new.returns(@wallet_mock)
@car_mock.expects.drive_to_movies
@wallet_mock.expects.pay_for_ticket("10.00")
@car_mock.expects.drive_home
person = Person.new(@car_mock)
person.go_to_movies
end
Currently, Hardstub isn’t smart enough to automatically revert the stubs, so make sure to call revert_stubs in teardown. Another tip, don’t stub very common classes such as File or Dir.
Update 4/11/07
There’s currently an issue that is keeping Hardmock from auto verifying, so until this is fixed, a work around is to put this in your teardown.
def teardown
verify_mocks
ensure
revert_stubs
# Other teardown code
end
There was a small bug with Depth Merge when merging nils without deleting them. Behavior should now be the same as the regular merge.
Original Article