Testing custom validators

When writing custom validators like described in the Rails guide on validations it’s good practice to write tests for them so you are sure they work as intended. Let’s take a look at the custom validator example shown in that Rails guide:

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
      record.errors.add attribute, (options[:message] || "is not an email")
    end
  end
end

The above validator will validate attributes against a regular expression to see if the value is a valid email address, if it is not a valid email address the error “is not an email” is added to the errors for that attribute.

You can test the validator by working with a test model class inside your test like so:

require "test_helper"

class EmailValidatorTest < ActiveSupport::TestCase
  class TestModel
    include ActiveModel::Model

    attr_accessor :email

    validates :email, email: true
  end

  test "recognizes a valid email address" do
    test_object = TestModel.new(email: "mark@without-brains.net")

    assert test_object.valid?
  end

  test "fails validation for an invalid email address" do
    test_object = TestModel.new(email: "no-email")

    refute test_object.valid?
    assert_equal ["is not an email"], test_object.errors[:email]
  end
end

By defining the TestModel class inside the test it will actually be named EmailValidatorTest::TestModel preventing clashes with other tests.

If you want to try the above code in a Rails project you can save the files as app/validators/email_validator.rb and test/validators/email_validator_test.rb respectively and then run the tests.