【问题标题】:Rails Engine host application classes in RSpec testsRails Engine 在 RSpec 测试中托管应用程序类
【发布时间】:2015-07-06 15:04:45
【问题描述】:

我有一个 Rails 引擎,其中包含链接到某些宿主应用程序类的方法(我知道这种类型的耦合很糟糕,但在这种情况下它是不可避免的)。

我需要测试使用主机类的方法,但在尝试对主机类进行加倍/模拟/存根时出现uninitialized constant MyEngine::BaseUser 错误(在本例中为BaseUserTutor)。

我曾尝试通过创建模拟类来解决这个问题,但我认为我留下的是一个坏主意,这意味着我的测试不太有用(见下文)。

知道我可以做得更好,或者对更好的方向提出建议吗?

正如我上面所说,我(糟糕地)这样解决了这个问题:

BaseUser = Class.new do
    attr_accessor :id

    def initialize(id = 1)
        @id = id
    end

    def self.find(id)
        self.new(id)
    end

    def tutor
        Tutor.find(self.id)
    end
end

class Tutor
    attr_accessor :id, :first_name

    def initialize(id = 1)
        @id = id
        @first_name = "Tutor with ID #{id}'s first name"
    end

    def self.find(id)
        self.new(id)
    end
end

it 'returns the hosts first name' do
    allow(MyEngine).to receive_message_chain(:user_class, :constantize) { BaseUser }
    ai = FactoryGirl.create(:availability_interval, host_id: 1)
    expect(ai.host_first_name).to eq BaseUser.find(1).tutor.first_name
end

我正在测试的方法是这样的:

def host_full_name
    MyEngine.user_class.constantize.find(self.host_id).tutor.full_name
end

MyEngine.user_class 是“基本用户”)

【问题讨论】:

    标签: ruby-on-rails testing rspec rails-engines


    【解决方案1】:

    您的引擎将所有内容命名为您的引擎。如果您尝试访问在基本范围内(即在您的引擎之外)实际定义的类,您可以使用:: 强制它在基本范围内查找该类,例如:

     expect(ai.host_first_name).to eq ::BaseUser.find(1).tutor.first_name
    

    【讨论】:

      【解决方案2】:

      我在问题中所做的似乎仍然是最好的解决方案,所以我继续用这种方法的另一个例子来回答这个问题。

      在这里我需要模拟/建模一个Setting,它在代码中(在引擎之外)像这样使用:my_value = Setting.find_by_name('SETTING_NAME').value

      describe 'ratable_based_on_time' do
      
          Setting = Class.new do
              def self.value
              end
              def self.find_by_name(name)
              end
          end
      
          before(:each) do
              allow(Setting).to receive_message_chain(:find_by_name, :value).and_return("30")
          end
      
          let(:availability_interval) { FactoryGirl.create(:availability_interval) }
      
          it 'should return availability_intervals that are rateable based on time since start' do
              availability_interval.update_column(:start_time, 1.hour.ago)
              availability_interval.reload
              expect(AvailabilityInterval.ratable_based_on_time).to eq [availability_interval]
          end
      
          it 'should not return availability_intervals that are not rateable based on time since start' do
              availability_interval.update_column(:start_time, 25.minutes.ago)
              availability_interval.reload
              expect(AvailabilityInterval.ratable_based_on_time).to eq []
          end
      end
      

      【讨论】:

        猜你喜欢
        • 2012-03-29
        • 2011-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-08
        相关资源
        最近更新 更多