使用Minitest测试自定义验证器

时间:2015-11-28 21:13:54

标签: ruby-on-rails validation unit-testing minitest custom-validators

我有多个带有电子邮件验证的模型。因此,我已将验证提取到自定义验证器中。我按照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中为自定义验证器编写此类测试(不使用规格!)?

2 个答案:

答案 0 :(得分: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 = "valid@email.com"
    assert_nil obj.errors[:email]
    assert obj.valid?
  end
end

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

HTH

答案 1 :(得分:0)

这是我根据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

非常酷的解决方案,也可用于其他测试。