使用 Minitest 测试自定义验证器
Testing custom validators with Minitest
我有多个具有电子邮件验证功能的模型。因此,我已将验证提取到自定义验证器中。我按照 Rails Guides.
的教程进行了此操作
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
record.errors[attribute] << (options[:message] || "is not an email")
end
end
end
到目前为止,还不错。但是因为我已经将电子邮件验证的功能提取到它自己的范围内,所以我也想单独测试它。我不想为每个模型添加相同的电子邮件格式测试。
我找到了另一个 question,它也问了同样的问题,但 RSpec。但是由于我还没有使用过存根和模拟,所以我不知道如何将测试移植到 Minitest 测试。我还没有找到任何使用 Minitest 测试自定义验证器的资源。
有谁知道如何在 Minitest 中为自定义验证器编写此类测试(不使用规范!)?
你在这里要求的(我认为)是在隔离中测试这个验证器。这意味着它会被测试一次,在一个独立的测试中,它会完全按照你说的做:
I don't want to add the same email format tests to every model.
我在这里采用的方法是在测试文件中只创建一个测试 class,混入 ActiveRecord::Validations
模块并测试 class 本身。
# test_file.rb
require 'test_helper'
class EmailValidatable
include ActiveModel::Validations
validates_with EmailValidator
attr_accessor :email
end
class EmailValidatorTest < Minitest::Test
def test_invalidates_object_for_invalid_email
obj = EmailValidatable.new
obj.email = "invalidemail"
refute obj.valid?
end
def test_adds_error_for_invalid_email
obj = EmailValidatable.new
obj.email = "invalidemail"
refute_nil obj.errors[:email]
end
def test_adds_no_errors_for_valid_email
obj = EmailValidatable.new
obj.email = "valid@email.com"
assert_nil obj.errors[:email]
assert obj.valid?
end
end
我没有测试上面的代码,但我认为它应该会给你一个 idea/direction。
HTH
这是我根据 Ile Eftimov 的回答实施的解决方案:
require 'test_helper'
class EmailValidatable
include ActiveModel::Validations
attr_accessor :email
validates :email, email: true
end
class EmailValidatorTest < ActiveSupport::TestCase
invalid_email_addresses = ['invalid email@example.com', 'invalid@ example.com', 'invalid@@example.com', 'invalid', 'invalid@example']
def obj; @obj ||= EmailValidatable.new; end
test 'should invalidate email address' do
invalid_email_addresses.each do |email|
obj.email = email
assert_not obj.valid?
end
end
test 'should add error for invalid email' do
invalid_email_addresses.each do |email|
obj.email = email
obj.valid?
assert_equal I18n.t('errors.messages.not_an_email_address'), obj.errors[:email][0], "no error message for invalid email address \"#{email}\""
end
end
test 'should validate email address' do
obj.email = FFaker::Internet.email
assert obj.valid?
end
test 'should add no error for valid email' do
obj.email = FFaker::Internet.email
assert obj.errors[:email].blank?
end
end
非常酷的解决方案,也可用于其他测试。
我有多个具有电子邮件验证功能的模型。因此,我已将验证提取到自定义验证器中。我按照 Rails Guides.
的教程进行了此操作class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
record.errors[attribute] << (options[:message] || "is not an email")
end
end
end
到目前为止,还不错。但是因为我已经将电子邮件验证的功能提取到它自己的范围内,所以我也想单独测试它。我不想为每个模型添加相同的电子邮件格式测试。
我找到了另一个 question,它也问了同样的问题,但 RSpec。但是由于我还没有使用过存根和模拟,所以我不知道如何将测试移植到 Minitest 测试。我还没有找到任何使用 Minitest 测试自定义验证器的资源。
有谁知道如何在 Minitest 中为自定义验证器编写此类测试(不使用规范!)?
你在这里要求的(我认为)是在隔离中测试这个验证器。这意味着它会被测试一次,在一个独立的测试中,它会完全按照你说的做:
I don't want to add the same email format tests to every model.
我在这里采用的方法是在测试文件中只创建一个测试 class,混入 ActiveRecord::Validations
模块并测试 class 本身。
# test_file.rb
require 'test_helper'
class EmailValidatable
include ActiveModel::Validations
validates_with EmailValidator
attr_accessor :email
end
class EmailValidatorTest < Minitest::Test
def test_invalidates_object_for_invalid_email
obj = EmailValidatable.new
obj.email = "invalidemail"
refute obj.valid?
end
def test_adds_error_for_invalid_email
obj = EmailValidatable.new
obj.email = "invalidemail"
refute_nil obj.errors[:email]
end
def test_adds_no_errors_for_valid_email
obj = EmailValidatable.new
obj.email = "valid@email.com"
assert_nil obj.errors[:email]
assert obj.valid?
end
end
我没有测试上面的代码,但我认为它应该会给你一个 idea/direction。
HTH
这是我根据 Ile Eftimov 的回答实施的解决方案:
require 'test_helper'
class EmailValidatable
include ActiveModel::Validations
attr_accessor :email
validates :email, email: true
end
class EmailValidatorTest < ActiveSupport::TestCase
invalid_email_addresses = ['invalid email@example.com', 'invalid@ example.com', 'invalid@@example.com', 'invalid', 'invalid@example']
def obj; @obj ||= EmailValidatable.new; end
test 'should invalidate email address' do
invalid_email_addresses.each do |email|
obj.email = email
assert_not obj.valid?
end
end
test 'should add error for invalid email' do
invalid_email_addresses.each do |email|
obj.email = email
obj.valid?
assert_equal I18n.t('errors.messages.not_an_email_address'), obj.errors[:email][0], "no error message for invalid email address \"#{email}\""
end
end
test 'should validate email address' do
obj.email = FFaker::Internet.email
assert obj.valid?
end
test 'should add no error for valid email' do
obj.email = FFaker::Internet.email
assert obj.errors[:email].blank?
end
end
非常酷的解决方案,也可用于其他测试。