【问题标题】:rspec testing delegation for module method undefined method模块方法未定义方法的rspec测试委托
【发布时间】:2020-01-18 21:42:42
【问题描述】:

这个模块被包含在 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

错误

失败/错误: 注册::Base::ActAsDelegation.delegate_fields_to(:user,:address)

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

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

【问题讨论】:

    标签: ruby-on-rails ruby rspec delegation ruby-on-rails-5.2


    【解决方案1】:

    由于您的模块设计为包含在内,因此只需将其包含在测试中的空类中即可。我准备了一个经过验证的简化示例:

    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
    

    另外,如果你害怕名字冲突,你可以创建匿名类。

    【讨论】:

    • 失败/错误:expect(user).to have_received(:first) (Double "user").first(*(any args)) 预期:1 次收到任何参数:0 次任何参数
    • 还有什么是匿名类?
    • 在检查它是否被委托给user之前,您不应该调用TestClass.new.first之类的东西吗?
    • 是的,这已在实际代码中得到纠正,现在一切正常。谢谢
    猜你喜欢
    • 2012-06-13
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多