Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing "validates ..., format => with"

I have a User model with this validation

validates :name, :lastname, :format => {:with => /^[a-zA-Z]+$/, :message => 'Only letters and spaces allowed.'}

I'm not sure how to properly test it.

I've done a function that returns a random string made by 10 chars from an array of a-zA-z chars.

def get_random_name
  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".split('').shuffle[0..10].join

end end

and then I get a new name for each run of my specs.

I don't want to test that it uses some regexp, because then I would be testing the implementation and not the behavior, and I also don't want to test only one hardcoded case.

My questions are: Should I do that? Is it really needed? Is it better or useless? Do you know any better way to test that kind of validations?

EDIT: another question, what about generating invalid random names? is there a way to create random names that includes at least one char outside the allowed values? I can't hardcode an array of all invalid values to randomize it since it would be TOO big

like image 517
arieljuod Avatar asked Jan 27 '13 05:01

arieljuod


2 Answers

Checkout the open-source project Shoulda Matchers: https://github.com/thoughtbot/shoulda-matchers

Edit: Sorry just noticed that Paul Fioravanti mentioned Shoulda also. However you don't need to use FactoryGirl to create instances of the model. Using create isn't necessary for a validation tests.

You can create unit tests directly on the model:


describe User, 'Validations' do
  it { should allow_value("Name").for(:name) }
  it { should_not allow_value("Inv4lid_").for(:name) }
end
like image 157
harlow Avatar answered Dec 31 '22 20:12

harlow


In order to test valid and invalid formats (I think a regex is fine to define a format to validate against), how about defining what you think valid and invalid names are in some helper utility methods that you could perhaps refine over time if necessary. For example:

spec/support/utilities.rb

def valid_names
  %w[Homer bart LISA]
end

def invalid_names
  %w[BuRn$ 5M1+h3Rs♡]
end

Then, you could write tests for :name (and :lastname) using RSpec, shoulda-matchers, and Factory Girl that look something like this:

spec/models/user_spec.rb

describe User do

  let(:user) { FactoryGirl.create(:user) }

  # ...

  describe "validations" do
    context "for name, lastname" do
      context "when format is invalid" do
        invalid_names.each do |invalid_name|
          it { should_not allow_value(invalid_name).for(:name) }
          it { should_not allow_value(invalid_name).for(:lastname) }
        end
      end

      context "when format is valid" do
        valid_names.each do |valid_name|
          it { should allow_value(valid_name).for(:name) }
          it { should allow_value(valid_name).for(:lastname) }
        end
      end
      # ...
    end
    # ...
  end
  # ...
end

If you ever intend to internationalize your app in the future, just remember that not all the world's names conform to this format.

like image 30
Paul Fioravanti Avatar answered Dec 31 '22 19:12

Paul Fioravanti