Using OpenStruct to Enhance Your Mocks

24 Mar 2007

So I use RSpec’s built in mocking framework for my mocking/stubbing and it works quite well. I sent up a mock like so:

mock_active_record_instance =
mock(“give it a name here, but probably a better one than this”)

and put some expectations on it like so:

mock_active_record_instance.should_receive(:id).and_return(1)

but some calls to the mock I don’t care about so I can stub them out like so:

mock_active_record_instance.stub!(:name).
and_return(“Arthur, King of the Britons”)

If I don’t need it to return anything I can leave off the and_return and it will return nil. But it’s tedious to do that. Lately I tend to use OpenStructs as my mocks like so:

mock_active_record_instance = OpenStruct.new
mock_active_record_instance.should_receive(:id).and_return(1)

Now here’s what’s cool about that: My spec(test) will fail if the expectation of a call to id isn’t met, but any other calls will be ignored (and nil returned). If I had made mock_active_record_instance a mock, like in the first example, I’d have to mock or stub out all the calls it’s going to get and that is just painful. This way I can ignore the stuff I don’t want to spec(test) painlessly.

You can also do fun stuff like so:

mock_active_record_instance = OpenStruct.new(:height => “5’10’’”,
:weight => 260,
:cars => [“hyundai”, “saturn”])

So now mock_active_record_instance.cars will return an array with 2 stings. And height will return “5’10’’” and weight will return 260. Maybe, in the future, a call to weight will return a smaller number – I’m working on it.

Warning – it may be that you have to do this because too many things are going on in the method you are specifying(testing). A better solution might be to figure out how to shorten up that method.

Jay Fields wrote about using OpenStructs in a series of blog posts about stubbing in rails which are totally worth reading.