[rspec-users] testing behaviour or testing code?

Jay Levitt lists-rspec at shopwatch.org
Sun Sep 2 18:14:53 EDT 2007

On 9/2/2007 12:43 PM, David Chelimsky wrote:
> The problem we face is that AR promises huge productivity gains for
> the non TDD-er, and challenges the thinking of the die-hard TDD-er.
> I've gone back and forth about whether it's OK to test validations like this:
> it "should validate_presence_of digits" do
>   PhoneNumber.expects(:validates_presence_of).with(:digits)
>   load "#{RAILS_ROOT}/app/models/phone_number.rb"
> end
> On the one hand, it looks immediately like we're testing
> implementation. On the other, we're not really - we're mocking a call
> to an API. The confusion is that the API is represented in the same
> object as the one we're testing (at least its class object). I haven't
> really done this in anger yet, but I'm starting to think it's the
> right way to go - especially now that we have Story Runner to cover
> things end to end. WDYT of this approach?

Personally, I don't much like it.  It feels too much like:

it "should validate_presence_of digits" do
   my_model.line(7).should_read "validates_presence_of :digits"

I can write specs like that all day and ensure absolutely nothing about 
my code.

I like to think of specs as a form of N-version programming where N=2 
(or maybe N=3 now with Story Runner).  By using a different vocabulary 
to express the specs than the actual code, we are more likely to think 
of the problem differently, and thus find places where the two versions 
of our code differ.  Sometimes, it means we miswrote the spec; 
sometimes, it means we miswrote the code.

But if all your spec does is guarantee that your code reads a certain 
way, you've done nothing but protect against accidental edits.  And if 
you're gonna go that way, why not go all the way:

it "shouldn't change unless I change the spec too" do
   MD5.new(my_model).should == "0xDEADBEEF0FFD2FFE4..."

I'd much rather see:

it "should prevent me from entering anything but digits" do
   PhoneNumber.new("800-MATTRESS").should_not be_valid

And then, every time I find an edge case, I add another spec:

it "should allow me to enter dashes" do
   PhoneNumber.new("800-555-1212").should be_valid

it "should only allow 10 digits" do
   PhoneNumber.new("800-555-12121212").should_not be_valid


Jay Levitt

More information about the rspec-users mailing list