[rspec-users] spec'ing validates_uniqueness_of :whatever

Steven Baker steven at stevenrbaker.com
Fri Apr 4 01:41:23 EDT 2008

> The test asserts that you call validates_uniqueness_of, but it doesn't
> actually test your logic.
> So it's useful to see if someone accidentally deletes your code, but  
> if you have
>    validates_uniqueness_of :user, :scope => :project_id
> or something more complex, it won't test this behavior.

One of the rules that I learned with TDD, that I brought with me to  
BDD, is that you only specify or test what you write.  Everything else  
is assumed to behave as intended.  This rule is, among other things,  
intended to keep us productive: we can't write a test suite for an  
entire framework every time we use that framework to implement an  
application.  At some point, we have to trust that the frameworky bits  
work as intended.

I don't exactly assume that the code I'm depending on is well tested,  
just that it's not my job to specify its behaviour.

If you were to write an example that creates two models, and ensures  
that the duplicate errored appropriately, my "rule" is violated.  Each  
of your examples is then specifying the behaviour of the  
validates_uniqueness_of method, which you didn't write.

Doing this with mocks ensures that you called validates_uniqueness_of,  
and doesn't test the behaviour of the method which, since you didn't  
write it, get to assume behaves as expected.  This is where my "rule"  
falls down: mocking the call prevents you from changing the  
implementation without changing the behaviour.

That is to say that you may want to, in the future, roll your own  
uniqueness validation that is called in a different way than  
ActiveRecord's, but behaves in the same way.  If you mocked, you could  
change the implementation without changing the behaviour, and still  
have a failing example.

This is where the line is drawn for me: I need to be able to change  
the implementation, and only have my examples fail when I've changed  
the behaviour.

So, in this case, using mocks and expecting Rails' built-in validation  
is fragile.  But in general, I try to stick to the "rule" (let's say  
guideline from now on) that I outlined above.


More information about the rspec-users mailing list