Monday, November 27, 2006

Ruby mocking - Using flexstub

Ruby proves to be as sweet as most people have claimed it to be.

Pick testing and and you hit flexmock and flexstub.

So how do you use them? Here goes:

You have

class CA{
def method_1
do_some_processing
if condition method_2
else method_3
end

def method_2
do_some_slow_processing_worth_mocking_out
end

def method_3
do_some_more_slow_processing_worth_mocking_out
end

}

If you want to test method_1's conditonal logic, with method_2 and method_3 stubbed out, here is how you do it with flexstub:


require 'flexmock'

class MyTest< Test::Unit::TestCase
include FlexMock::TestCase
def test_method_1
ca = CA.new
# do something to make the condition be true
# stub some methods of the instance
stub = flexstub(ca)
stub.should_receive(:method_2).once
stub.should_receive(:method_3).never
ca.method_1
# Note: method_1 is invoked on ca.
# stub.method_1 will fail!
end
end


So when would you use flexmock?
If you wish to mock all the methods being called on an object, you may use a flexmock.
A flexmock is an object which will just receive the methods you set expectations for, using should_receive.
If you wish to mock only one of the methods of an object but the other methods need to be invoked with the real functionality,
use flexstub to mock only that particular method.

As you see, method_1 is invoked properly, but method_2 and method_3 are stubbed out.

One remarkable thing about this is mocking out an object's new method.

flexstub(Customer).should_receive(:new)
.and_return(mock_customer)

Anywhere Customer.new is called inside any class during your test, it will return a mock_customer.
This is quite powerful, because we no longer need to use dependancy injection for just test purposes.

3 comments:

WolfDancer said...

Cool! I definitely need to check it out.

FYI, I am using rspec nowadays, which also has similar stuff built in. http://rspec.rubyforge.org

James Mead said...

You might also be interested in Mocha which, as Jim Weirich acknowledges, inspired the flexstub() aspect of FlexMock. Personally I prefer the Mocha syntax...

flexstub(Customer).should_receive(:new)
.and_return(mock_customer)

becomes...

Customer.expects(:new).returns(mock_customer)

... but I'm obviously biased ;-)

Narayan Raman said...

Checking out Mocha... Will post my feedback on that too.