Jake Scruggs

writes ruby/wears crazy shirts

So yesterday Leah and I were working on SudokuScanner -- a cool little site that will, when it's released, allow you to upload images of Sudoku boards and get a solution. All of a sudden, our mocks and stubs went totally batshit. One minute she and I were happily writing some tests, making them pass, refactoring, checking in, etc... and then, we got a bunch of failures. OK, no problem -- we must have busted something with our latest change. The failure was a mock expectations error: UserMailer expected to receive a call to deliver_activation but did not receive it. So we went over to the failing spec and... There was no expectation on UserMailer anywhere in the spec.

That's bad.

Ran the spec by itself and it passes.

Yep - not so good.

Reverse the order that the specs run in (spec --reverse) and a different number of specs fail, but still with the same expectation failure. And of course these new specs all pass on their own. And have no reference to UserMailer anywhere in them. I searched the project and only one spec has one expectation on UserMailer.deliver_activation, but now I have 10 failing specs that are all failing because of that expectation.

So it appears the mocking framework isn't cleaning up after itself -- Yipes!

After a bunch of exploring/messing about I found myself in the spec_helper.rb file and I noticed something weird: The line 'config.mock_with :mocha' that should not be commented out is commented out. Which is weird because we're using Mocha as our mocking framework. So I uncomment it and run all the specs through rake. A billion errors all saying some variation of "method stub! does not exist" or "method should_receive does not exist."

Got it.

So it seems we are using RSpec's built in mocking framework on this project, but somebody started using Mocha too. Full disclosure: That somebody is probably me. I've been bouncing between a bunch of projects lately and some of them use Mocha and some use RSpec's mocking framework. I probably task switched over and started using Mocha without thinking about it and it just worked. I have Mocha installed as a gem on my machine and maybe that's enough, or maybe one of our plugins or gems requires it, but it's there apparently in the load path so everything was fine for awhile. Of course mocking frameworks do some pretty intense meta-craziness under the covers so it was bound to happen that using both would lead to one screwing up the other's functionality like, say, breaking Mocha's ability to clean up after itself. Which lead to our pile of nutty failures.

Luckily changing over to from Mocha to RSpec's mocking framework is not hard so we were able to purge the mocha syntax from the project and all was made well.

I could write a test that looks at all of my test files for Mocha syntax... Or is there a way to un-require Mocha explicitly so this doesn't happen again?


Anonymous said...

I have hit something like this, and I believe I determined that Rails internal use of Mocha had spilled over into my tests.