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.