Делегирование тестирования rspec для метода модуля undefined method

Этот модуль включается в объект формы в рельсах.

Как правильно проверить это с помощью rspec?

1) Нужно ли тестировать его непосредственно на каждой модели, в которую он входит?

or

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

ИСПЫТАНИЯ РСПЕЦ

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

ОШИБКА

Сбой/ошибка: 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

(В этом примере у меня есть другие проблемы с кодом, но ниже устранена основная проблема)


person user2012677    schedule 18.09.2019    source источник


Ответы (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

Кроме того, вы можете создать анонимный класс, если боитесь конфликтов имен.

person katafrakt    schedule 18.09.2019
comment
Ошибка/ошибка: expect(user).to have_received(:first) (Double user).first(*(любые аргументы)) ожидаемый: 1 раз с любыми полученными аргументами: 0 раз с любыми аргументами - person user2012677; 18.09.2019
comment
И что такое анонимный класс? - person user2012677; 18.09.2019
comment
Разве вы не должны вызывать что-то вроде TestClass.new.first перед проверкой, было ли оно делегировано user? - person katafrakt; 19.09.2019
comment
Да, это было исправлено в реальном коде, теперь все работает. Спасибо - person user2012677; 19.09.2019