Should we write specs for validations?
When I was starting with TDD in Rails, I had times when I wasn’t really sure what to test for. Some of the apps were so simple that there wasn’t really that much to test, but I wanted to practice. I wanted to keep writing code.
I had this inner conflict about testing validations. At least for me, validations were kind of like getters and setters in their complexity. You don’t generally write a test case for a getter unless it has some additional logic inside.
But then I started stumbling upon cases where I forgot to validate some fields, or I put a wrong model in. Yes, even that can happen when you have a Post and a Comment model and they both have content field, it’s pretty easy to see validates_presence_of :content and not realize that you’re looking at a different model.
That’s how I ended up writing specs for validations. Nothing too complicated, just
it "requires a content" do
build(:post, content: nil).should_not be_valid
end
or a little more complicated
it "requires a content" do
post = build(:post, content: nil)
post.should have_at_least(1).error_on(:content)
end
is this an overkill? Someone might suggest that I’m wasting time writing such specs, but am I really?
Being a programmer, I can type pretty fast, according to typing speed test about 110 words per minute for english text, so writing a little validation spec takes almost no time.
Another important thing is that you don’t really need to think when writing the spec. You can think about the next thing you’re going to test. Programming isn’t just about typing, it’s more about thinking, and you can type while thinking about something else, if the thing you’re typing is completely automatic.
It might even be smart to use a code snippet for something like this, but I like to type it all out. It gives me a time to think about how exactly am I going to test the rest of the class.
it "has a valid factory" do
build(:post).should be_valid
end
it "requires a title" do
post = build(:post, title: nil)
post.should have_at_least(1).error_on(:title)
end
it "requires a content" do
post = build(:post, content: nil)
post.should have_at_least(1).error_on(:content)
end
Writing this took me exactly 53.4 seconds (yes I measured it) without using any code snippets or anything like that. I also made a bunch of typos and didn’t copy anything. You could easily ust copy the title spec and change title for content and save some time.
Even if I have a not-so-small application with say 20 different models, writing validation specs for all of them will take me a unimaginably long 20 minutes!
The important thing to note here is that this is not testing the framework. Validation tests are not here to prove that Rails works, at least not for me. They’re to give me the confidence that my basics are working as expected.
There’s nothing more frustrating than spending countless hours tracing a bug - only to realize that some of your most basic expectations were wrong, such as every user has a unique email. Imagine if you forgot that validation, and then implemented some kind of find one user by email search which will always yield the first result, so the next user who signs up with the same email address will never appear in the search result.
I know this is kind of a beginner mistake, and it probably makes you think of course I’d check the validation first, but would you really? Did it ever happen to you, that you were so sure about something being simple and correct, that you didn’t test for it at all, only to have it bite you in the ass later?
I used to write tests only for parts of code that were doing something complicated, relying on my simple stuff to just work. The thing is, if you trust your work too much, it will almost always come back to bite you.
When tracing a bug, it’s always important to remember to verify your expectations. If you’re sure that something is true, prove it. If you know that the form is being submitted and saved correctly, write a little test scenario where you fill in the form, submit it, and actually check that all of the values are entered. You might find that some attributes are protected and simply not being saved because you’re using mass assign.
I’m not trying to say that you should always write validation specs for everything. For me, it is kind of like view specs. They can be incredibly handy, especially if your views contain some kind of logic, or you have a bug that is hard to replicate.
In that case, view specs can give you that little missing piece of confidence, they can tell you that the problem is not in the way your view renders, they can tell you that the user does see what he’s supposed to see, and that the problem is somewhere else.
The bottom line is that figuring out where the bug isn’t will help you realize where the bug actually is?