Testing model validations in rspec the short and sweet way

There seems to be a divide in the Rails/TDD community over whether you should bother testing your model validations. On the one hand, it’s silly to just retest what the Rails core team has hopefully already tested — that validations work. On the other hand, I want to make sure that my models only accept the data that I design them to accept. I also tend to use my RSpec unit tests as blueprints for building out my models, in true TDD fashion, so I start out by defining what values they should accept.

For a while I was writing lots of tests like this:

[gist id=3afc8d4fd84c56b029e4 file=my_spec.rb]

The first assertion makes sure that we can create a new instance of the model given valid attributes. Once that passes we can start testing the negative assertions. The next block of code asserts that we can’t create a new instance with various invalid name attribute values, and then that we can create a new instance with valid name attribute values. Some might find this approach to be overkill, but I find it reassuring. I do not enjoy writing these bulky tests for models that have a half-dozen attributes or more, however. It leads to way too much test code to maintain. So I started poking around for alternatives. (Web development rule #1: Google it! Someone, somewhere, at some point has surely encountered this problem before you.)

A colleague pointed me in the direction of a plugin named rspec_validation_expectations, and the description seemed promising:

Instead of writing specs to verify that your models are handling validation correctly, these expectations simply check that the validation is getting declared correctly in your model. […] Since the expectations never hit the database, they are also faster than testing the traditional way.

Unfortunately, it hadn’t been updated since January 2010 and wasn’t compatible with Rails 3. (Or at least I couldn’t get it to work with Rails 3 after adding it to my Gemspec file.) So, the search continued and I came across a couple different solutions, most notably the matchers included with Shoulda and Remarkable. But after looking closely at those options it felt like too much duplication — in other words the specs ended up looking almost exactly like the AR validations you were testing which seemed too prone to copy/paste errors.

Finally I stumbled across a year-old post that discussed the same annoyance that I was facing: managing really long tests for simple validations. And more importantly, it offered a solution – accept_values_for. This gem basically provides all of the functionality I was writing out above, but in a very compact way. So I could replace all of that really long code from above with something much easier to maintain:*

[gist id=3afc8d4fd84c56b029e4 file=my_thinner_spec.rb]

Very nice, very simple, and not too tedious. So, how do you test model validations?

* You can even get more compact assertions with accept_values_for using the compact form of it { should_not accept_values_for(:name, nil, "a", "a" * 201) }, I just chose to break mine out into separate assertions for each value so that the success/failure messages were more specific.

5 thoughts on “0

  1. Hi. I just gave this a go and it is brilliant. It has already saved me lots of tedious coding and time

  2. Very helpful discussion. I did the same verbose and brittle first approach. Will try this approach. So appreciate you sharing your thought process in such a clear and thoughtful way.

Comments are closed.

Without requirements or design, programming is the art of adding bugs to an empty text file.