如何在Rails 4中的模型关注中测试验证?

时间:2015-10-15 07:13:49

标签: ruby-on-rails rspec

我有一个模型关注点进行验证:

module UserValidations
  extend ActiveSupport::Concern

  VALID_EMAIL_REGEX = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i

  included do
  validates :email,
            :presence   => true,
            :format     => VALID_EMAIL_REGEX,
            :uniqueness => { case_sensitive: false }
  end
end

此问题用于多种形式。

现在我打算为这个问题编写规范,所以我不需要在不同的表单规范中测试相同的验证集。但是,我还没有找到一个好方法......

我尝试过这样的事情却失败了......

require 'spec_helper'

class DummyClass
  include ActiveModel::Validations
  include ActiveRecord::Validations
  include UserValidations

  attributes :email, :first_name, :last_name
end

describe "UserValidations" do
  subject { DummyClass.new }

  it { is_expected.to validate_presence_of :email }
end

错误堆栈:

/home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/term-ansicolor-1.3.2/lib/term/ansicolor.rb:239:in `term_ansicolor_attributes': wrong number of arguments (3 for 0) (ArgumentError)
  from /home/eyang/grasshopper_dev/gh_user_service/spec/models/concerns/user_validations_spec.rb:8:in `<class:DummyClass>'
  from /home/eyang/grasshopper_dev/gh_user_service/spec/models/concerns/user_validations_spec.rb:3:in `<top (required)>'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:268:in `load'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:268:in `block in load'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:240:in `load_dependency'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:268:in `load'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1327:in `block in load_spec_files'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1325:in `each'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1325:in `load_spec_files'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:102:in `setup'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:88:in `run'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:73:in `run'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:41:in `invoke'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-3.3.2/exe/rspec:4:in `<top (required)>'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/bin/rspec:23:in `load'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/bin/rspec:23:in `<main>'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/bin/ruby_executable_hooks:15:in `eval'
  from /home/eyang/.rvm/gems/ruby-2.0.0-p594/bin/ruby_executable_hooks:15:in `<main>'

2 个答案:

答案 0 :(得分:0)

将关注点包含在虚拟类中是有帮助的。这个问题并不完全相同,但它证明了这种方法:

Rails & RSpec - Testing Concerns class methods

答案 1 :(得分:0)

不确定以下测试在Rails应用程序的上下文中的效果如何,但以下是我尝试尽可能一般地测试您的UserValidations问题。您应该能够将代码复制并粘贴到文件中并在其上运行rspec进行测试,然后您可以将其集成到项目中,如果它适合您:

require 'active_record'
require 'active_model'
require 'active_support'
require 'shoulda-matchers'

module UserValidations
  extend ActiveSupport::Concern

  VALID_EMAIL_REGEX = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i

  included do
    validates :email,
              :presence   => true,
              :format     => VALID_EMAIL_REGEX,
              :uniqueness => { case_sensitive: false }
  end
end

ActiveRecord::Base.establish_connection(
  adapter: 'sqlite3', database: ':memory:'
)

# Create an 'anonymous' table that has an email field
ActiveRecord::Schema.define do
  create_table :'' do |t|
    t.string :email
  end
end

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :active_record
    with.library :active_model
  end
end

RSpec.describe UserValidations, type: :model do
  let(:user_validate_able) do
    # Instantiate an anonymous class that inherits from AR::Base
    Class.new(ActiveRecord::Base) do
      include UserValidations

      # ActiveModel needs a model name for error messages,
      # so give one to this anonymous class
      def self.model_name
        ActiveModel::Name.new(self, nil, 'AnonymousModel')
      end
    end.new
  end

  it 'validates presence, uniqueness, and format of email' do
    expect(user_validate_able).to validate_presence_of(:email)
    expect(user_validate_able).to validate_uniqueness_of(:email).case_insensitive
    expect(user_validate_able).to allow_value('guy@incognito.com').for(:email)
  end
end