At Financeit, our main app uses RSpec for the test suite, but until recently it made use of Mocha (not to be confused with the JavaScript library of the same name) for stubbing and mocking.
We recently decided to switch to use rspec-mocks. Some reasons for this were:
- We were already using rspec-mocks in other projects.
- There are more reference and training materials for rspec-mocks (books, screencasts, blog posts, etc).
- New developers joining the team were typically already familiar with rspec-mocks.
We didn’t have any problem with Mocha itself – it’s well-designed, has good documentation, and a responsive maintainer. The main reason was to have a simple and consistent stack.
Approach
As our test suite is large, we knew that an incremental approach would be preferable.
We made use of the rspec-multi-mock gem to allow Mocha and rspec-mocks to both be used at the same time.
We then introduced a policy that new specs should be written using rspec-mocks rather than Mocha. Our code review process helped to remind developers of this.
Next, we began the process of converting the test suite. Most Mocha has a direct mapping to rspec-mocks. I created this ‘cheatsheet’ for easy reference:
Mocha | rspec-mocks |
---|---|
stub(a: 1) |
double(a: 1) |
mock(a: 1) |
double(a: 1) |
foo.stubs(:a).returns(1) |
allow(foo).to receive(:a).and_return(1) |
foo.expects(:a).returns(1) |
expect(foo).to receive(:a).and_return(1) |
Foo.any_instance.stubs(:a).returns(1) |
allow_any_instance_of(Foo).to receive(:a).and_return(1) |
The most obvious way to make these conversions would be using regular expressions. And although this handles around 80% of conversions, the remainder would need to manually reviewed and edited, or would need very complex regular expressions.
As a general rule when changing code with automatic tools, it’s better to modify the AST (Abstract Syntax Tree) than to manipulate strings.
Ruby already has a powerful tools for this: RuboCop, which makes use of theparser gem, has an auto-correct feature to change code to follow a preferred style.
RuboCop Custom Cops
At Financeit, we have a concept of ‘spike weeks’ where developers get to work on something they have a personal interest in. This gave me an opportunity to explore this area.
RuboCop can be extended with custom cops – the documentation is somewhat limited, so it took some time to get the hang of, but after that I found it to be a very effective approach.
I worked through the app in stages, beginning with spec/controllers
, thenspec/models
, spec/services
, etc.
The test suite itself helped to verify that the conversions were correct, since bad conversions should typically result in a syntax error, or a failing test.
I ran into a few situations where the conversion didn’t work because of some strange approaches in the test, so took the opportunity to re-write the test.
We’ve now converted around 95% of the test suite. We hope to soon reach 100%, when we can then remove the rspec-multi-mock and Mocha gems.
I’ve published the RuboCop custom cops as the mocha_to_rspec gem.
Top comments (0)