Shoulda macros are so neat and tidy, aren’t they? I love kicking off my unit tests with quick-and-deadly validation and association tests. Here’s an example:
require 'test_helper' class CouponTest < ActiveSupport::TestCase should_validate_presence_of :code, :name, :description context "validating uniqueness" do setup do Factory :coupon end should_validate_uniqueness_of :code end should_belong_to :user end
Do you see anything wrong with this picture? should_validate_uniqueness_of
necessarily requires that you already have a record in the database. As much as I hate database interaction in my tests, it’s a necessary evil here. The macro works by copying the attributes of an existing record, and validating it to see if you get any uniqueness errors. So, for this one test, I have to setup a context with a Factory call, because I’m not about to create a record for all the other tests that don’t need it.
Wouldn’t it be nice if you could call should_validate_uniqueness_of
and it would create the record for you, if one didn’t already exist? It could use the Factory you’ve already setup. And it would still work the old way if you don’t have factories, or don’t enjoy DRY coding.
Add this macro to your application:
# test/shoulda_macros/validation_macros.rb module Test module Unit class TestCase class << self alias_method :svuo_original, :should_validate_uniqueness_of def should_validate_uniqueness_of(*attributes) class_name = self.name.gsub(/Test$/, '') klass = class_name.constantize model_sym = class_name.underscore.to_sym context "with a record in the database" do setup do Factory model_sym unless klass.count > 1 end svuo_original *attributes end end end end end end
Here, we’re overriding the default Shoulda macro. Before we call the original, we’ll setup a context and create the record using our Factory, unless a record is already created. That means it will always “just work”, with the exact same syntax, and all of the options of the original should_validate_uniqueness_of
Thoughtbot can’t create the macro like this by default, because it assumes you have factory_girl
installed. But if you do use factories, this upgrade will take some of the ugly out of your tests:
require 'test_helper' class CouponTest < ActiveSupport::TestCase should_validate_presence_of :code, :name, :description should_validate_uniqueness_of :code should_belong_to :user end
Nice, eh? As usual, all you need to do to install/create a new shoulda macro is drop a ruby file into the test/shoulda_macros
folder, with macro methods defined. You don’t even need to reopen TestCase the way I did, unless you’re overriding an existing macro.
Tags: developers, macros, Rails, Ruby, ruby on rails, shoulda, Testing, unit, validates_uniqueness_of
January 19, 2010 at 1:54 pm |
You should show the code snippets by default and your first snippets needs quotation marks instead of the ampersand-quot-semicolon thing.
January 19, 2010 at 2:07 pm |
And YOU should know that I was merely testing you. You passed…barely :) I’ve corrected the ampersand problem, but I’m torn about showing code by default. It just makes the page so freaking long.
April 30, 2010 at 9:12 pm |
This worked perfectly. Thanks for sharing.