rspec 模块方法未定义方法的测试委托

rspec testing delegation for module method undefined method

此模块包含在 rails 中的表单对象中。

使用 rspec 测试它的正确方法是什么?

1) 我是否直接在包含它的每个模型上测试它?

2) 是否直接测试委托方法? (如果可能我更喜欢直接)

如果我直接测试,怎么样?我尝试并得到以下错误...

表单对象模块

module Registration
  class Base
    module ActAsDelegation
      def self.included(base)
        base.extend(ClassMethods)
      end

      module ClassMethods
        def form_fields_mapping
          [ 
            {name: :first, model: :user},
            {name: :address, model: :address}
          ]
        end

        def fields_of_model(model)
          form_fields_mapping.select {|record| record[:model] == model }.map {|record| record[:name] }
        end

        def delegate_fields_to(*models)
          models.each do |model|
            fields_of_model(model).each do |attr|
              delegate attr.to_sym, "#{attr}=".to_sym, to: model if attr.present?
            end
          end
        end
      end
    end
  end
end

表单对象

module Registration
  class Base
    include ActiveModel::Model
    include ActAsDelegation

    def initialize(user=nil, attributes={})
      error_msg = "Can only initiate inherited Classes of Base, not Base Directly"
      raise ArgumentError, error_msg if self.class == Registration::Base

      @user = user
      setup_custom_accessors

      unless attributes.nil?
        (self.class.model_fields & attributes.keys.map(&:to_sym)).each do |field|
          public_send("#{field}=".to_sym, attributes[field])
        end
      end
      validate!
    end
  end
end

RSPEC 测试

require "rails_helper"

RSpec.describe Registration::Base::ActAsDelegation, type: :model do

  describe "Class Methods" do
    context "#delegate_fields_to" do
      let(:user) {spy('user')}
      let(:address) {spy('address')}
      let(:delegation_fields) {          [ 
            {name: :first, model: :user},
            {name: :address, model: :address}
          ]}

      it "should delegate" do
        allow(subject).to receive(:form_fields_mapping) { delegation_fields }
        Registration::Base::ActAsDelegation.delegate_fields_to(:user,:address)
        expect(user).to have_received(:first)
        expect(address).to have_received(:address)
      end
    end
  end
end

错误

Failure/Error: Registration::Base::ActAsDelegation.delegate_fields_to(:user,:address)

 NoMethodError:
   undefined method `delegate_fields_to' for Registration::Base::ActAsDelegation:Module
   Did you mean?  delegate_missing_to

(我在这个例子中还有其他代码问题,但下面解决了主要问题)

由于您的模块旨在包含,因此只需将其包含在测试中的空 class 中。我准备了一个简化的例子,我验证它可以工作:

module ToBeIncluded
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def a_class_method
      :class
    end
  end
end

class TestSubject
  include ToBeIncluded
end

require 'rspec/core'

RSpec.describe ToBeIncluded do
  subject { TestSubject }

  it 'returns correct symbol' do
    expect(subject.a_class_method).to eq(:class)
  end
end

在你的情况下,可能按照这些思路应该没问题:

require "rails_helper"

RSpec.describe Registration::Base::ActAsDelegation, type: :model do
  class TestClass
    include Registration::Base::ActAsDelegation
  end

  describe "Class Methods" do
    context "#delegate_fields_to" do
      let(:user) {spy('user')}
      let(:address) {spy('address')}
      let(:delegation_fields) {          [ 
            {name: :first, model: :user},
            {name: :address, model: :address}
          ]}

      it "should delegate" do
        allow(TestClass).to receive(:form_fields_mapping) { delegation_fields }
        TestClass.delegate_fields_to(:user,:address)
        expect(user).to have_received(:first)
        expect(address).to have_received(:address)
      end
    end
  end
end

此外,如果您害怕名字冲突,您可以匿名class。