I’ve learned to test almost to a fault, though I’m not really sure you can take it that far. If you write tests at every layer of your app, then you don’t have to deal with trying to do to much in any one test. If my model methods are well tested, then I can mock them out without guilt in my controller layer and focus only on what the controller is suppose to do for instance. If you keep your layers well tested independently, then it’s easier to maintain.
One thing I’ve struggled with in the past is how to test validations and associations in model tests. Historically what I would do is this. Say I have a model (Blarf) that has some required attribute (fluggle):
class Blarf < ActiveRecord::Base validates_presence_of :fluggle end
In order to test this, I would rely on the ActiveRecord validations to trigger an error like so:
describe Blarf do
describe "Validations" do
describe "#fluggle" do
it "is a required field" do
model = Blarf.new
model.should_not be_valid
model.errors.on(:fluggle).should_not be_nil
end
end
end
end
While this works, and makes sure the field is always required it’s too heavy and invasive. Just like I assume the other layers of my code are well tested so I only need to test the appropriate layer at hand (see the model/controller example above) I make the same assumption about the frameworks/plugins I use. If I uncover an issue in them, then I fork the repo and fix it there (by starting with a failing regression test) using the same approach if the bug is found in my code. What’s always bothered me about my validation tests in the past is that I shouldn’t have to test that the AR validations work, only that they are in place. The same goes for testing associations.
So imagine my joy when I recently uncovered the rspec_validation_expectations plugin from Matthew Bass. It leverages the goodness of the validation_reflection plugin to give you helpers to make assertions about existing validations and associations. In the overly simplistic example above, it now becomes simply:
describe Blarf do
describe "Validations" do
it_should_validate_presence_of :fluggle
end
end
The great thing is that it doesn’t test the validation, only that it exists. It introspects on the class to make sure that your “validates_presence_of” code is present. It comes out of the box with the following validation helpers:
- it_should_validate_presence_of
- it_should_validate_numericality_of
- it_should_validate_uniqueness_of
- it_should_validate_inclusion_of
- it_should_be_createable
I’ve forked it and added the following (I’ll be submitting a patch to get these folded back in once I think I’m done with what I need):
- it_should_validate_length_of
- it_should_validate_confirmation_of
- it_should_validate_format_of
It also has helpers for associations. The following are already coded:
- it_should_belong_to
- it_should_have_many
- it_should_have_and_belong_to_many
- it_should_have_one
I love the amount of code this has removed from my model tests. It’s clean, concise, and more to the point of surgical testing. I am happy to write tests around any custom model behavior I build, and this gives me a way to make sure all my association and validation hooks from ActiveRecord are in place without having to write code to make sure AR is doing its job. Less code and better coverage works for me!