Minimalist RSpec Matching


Thu Feb 07 19:08:00 -0800 2008

I’ve been thinking about the “too much magic” problem of RSpec. There are two sides to this: too much magic in its internals, and too much magic in its matcher syntax. These are related. Shoulda and test_spec are popular because people like asserts. You never forget the syntax for assert_equals - at least, once you can remember the order the arguments go in (I always want to write the value first and the expected value second).

Lately I’ve made peace with this by limiting my use of RSpec’s matchers to just a couple of syntaxes:

var.should == 'expected'
var.should match(/pattern/)
var.should be_true   # or be_false
lambda { ... } should raise_error(SomeException)

These are easy to remember and they read nicely. var.should == ‘expected’ is nearly as good as assert_equal in its simplicity, with the further benefit that the expected value goes on the right, which I find more natural.

Very occassionaly I will use var.should > 0, but that’s about it. I also rarely find much use for should_not, except sometimes against a match. All of the other matchers I now avoid. Here’s a conversion chart from the ‘standard’ RSpec way to Adam’s minimalist approach:

RSpec Full Minimalist
item.should be_kind_of(Item) item.class.should == Item
file.should be_exists file.exists?.should be_true
cart.should have(3).items cart.items.size.should > 3

The argument against my approach is that it gives RSpec slightly less information about what’s failing. My experience so far has been that it’s been more than offset by the peace of mind of having less to rememeber. Actually, the peace of mind is because I no longer have to mentally scold myself every time I forget the right matcher to use.

I also feel that val.should == 1 has a distinctive look that’s easy to scan a page for. Not quite as good as assert, but close.