Why validation matchers are the only Shoulda matchers I use

by Jason Swett,

One of the testing questions I commonly get is about Shoulda matchers. People ask if I use Shoulda matchers and if Shoulda matchers are a good idea.

I’ll share my thoughts on this. First I’ll explain what Shoulda is, then I’ll explain why the only Shoulda matchers I use are validation matchers.

What Shoulda is

If you’re unfamiliar with Shoulda matchers, the premise, from the GitHub description, is: “Shoulda Matchers provides RSpec- and Minitest-compatible one-liners to test common Rails functionality that, if written by hand, would be much longer, more complex, and error-prone.”

A few examples of specific Shoulda matchers are validates_presence_of (expects that a model attribute has a presence validator), have_many (expects that a has_many association exists), and redirect_to (expects that a redirection takes place).

I like the idea of a library that can clean up a lot of my repetitive test code. Unfortunately, the majority of Shoulda matchers only apply to the kinds of tests I would never write.

Test behavior, not implementation

To me it doesn’t make much sense to, for example, write a test that only checks for the presence of an Active Record association and doesn’t do anything else.

If I have an association, presumably that association exists in order to enable some piece of behavior, or else it would be pointless for the association to exist. For example, if a User class has_many :posts, then that association only makes sense if there’s some Post-related behavior.

So there are two possibilities in light of testing that the User class has_many :posts. One is that I write a test for both the association itself and the behavior enabled by the association, in which case the test for the association is redundant and adds no value. The other possibility is that I write a test only for the post association, but not for the post behavior, which wouldn’t make much sense because why wouldn’t I write a test for the post behavior?

To me it only makes sense in this example to write tests for the post behavior and write no tests directly for the association. The logic of this decision can be proved by imagining what would happen if the has_many :posts line were removed. Any tests for the post behavior would start failing because the behavior would be broken without the association line present.

Why validation matchers are different

I mentioned at the top of the post that validation matchers are the only Shoulda matchers I use. The reason I do use Shoulda matchers is because validations aren’t just a means to an end, they’re an end in themselves. In other words, validations are a feature.

The alternatives to using Shoulda matchers to check for validations are to not write validation tests at all or to write really repetitive tests for validations. Both those alternatives seem bad to me, so Shoulda matchers it is.

  •  
  •  
  •  
  • 18

4 thoughts on “Why validation matchers are the only Shoulda matchers I use

  1. Pito Salas

    You never explained why shoulda matchers are used only for testing associations? I thought there are as general as any other matches, just more succinct.

    Reply
    1. Jason Swett Post author

      I don’t use Shoulda matchers only for testing associations, I use Shoulda matchers only for testing validations. I don’t use Shoulda matchers for associations.

      Reply
  2. Justin Craig-Kuhn

    You say it doesn’t make sense to write a test that checks only for the presence of an ActiveRecord association, but why would you write a test for behavior that is already covered in Rails core? Do you extend this concept to every feature in every gem you include?

    Reply
    1. Jason Swett Post author

      If your argument is that it’s pointless to write tests for validations, then I reluctantly admit that that’s actually a pretty good point. Writing a test for the presence of a validation isn’t as illogical as writing a test for the presence of e.g. a has_many association, but it’s still of dubious value.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *