使用Minitest测试自定义validation器

我有多个模型与电子邮件validation。 因此,我已将validation提取到自定义validation器中。 我按照Rails指南的教程来说明这一点。

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

到现在为止还挺好。 但是,由于我已经将电子邮件validation的function提取到了自己的范围内,我还想单独测试它。 我不想为每个模型添加相同的电子邮件格式测试。

我发现了另一个问题 ,但也对RSpec提出了同样的问题 。 但由于我还没有使用存根和模拟,我不知道如何将测试移植到Minitest测试。 我没有找到任何用Minitest测试自定义validation器的资源。

有人知道如何在Minitest中为自定义validation器编写此类测试(不使用规范!)?

我在这里要求的是单独测试这个validation器。 这意味着它将在隔离测试中进行一次测试,这将完全按照您的说法进行测试:

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

我在这里采用的方法是在测试文件中创建一个测试类,混合使用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

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

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