RSpec测试中的Rails Engine主机应用程序类

时间:2015-07-06 15:04:45

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

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

我需要测试使用主机类的方法,但在尝试加倍/模拟/存根主机的类时uninitialized constant MyEngine::BaseUserBaseUser或在这种情况下Tutor。)

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

知道我可以做得更好,还是建议更好的方向进入?

正如我上面所说,我(这很糟糕)就这样:

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是" BaseUser")

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

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

在这里,我需要模拟/模拟代码中使用的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