3

我有多个使用电子邮件验证的模型。因此我将验证提取到自定义验证器中。我按照Rails Guides的教程进行操作。使用Minitest测试自定义验证器

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中编写自定义验证器的测试(不使用规范!)?

回答

3

你在这里要求的是什么(我认为)是在隔离测试验证器。这意味着它将在隔离测试中进行一次测试,它将完全按照您的说法进行测试:

我不想为每个模型添加相同的电子邮件格式测试。

我想在这里采用的方法是在测试文件中创建一个测试类,混合ActiveRecord::Validations模块并测试类本身。

# 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 = "[email protected]" 
    assert_nil obj.errors[:email] 
    assert obj.valid? 
    end 
end 

我还没有测试过上面的代码,但我认为它应该给你一个想法/方向。

HTH

+0

这正是我所寻找的。我从来没有想过创建一个新课程并从那里进行测试。我一直在寻找如何直接测试的方法。但是这看起来更好!谢谢! – Tobias

+0

太棒了,我很高兴我的帮助。你能否对你的全部测试进行评估?谢谢:) –

+0

Hi @Ile!我已经将我实施的解决方案添加为答案。再次感谢你! – Tobias

0

这里的基础上岛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 protected]', '[email protected] example.com', '[email protected]@example.com', 'invalid', '[email protected]'] 

    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 

真是太爽了解决方案,也为其他测试使用。