如何测试基于其他模型的动态定义方法

时间:2013-09-16 05:22:28

标签: ruby-on-rails ruby ruby-on-rails-3 rspec rspec-rails

我有一个名为DeviceState的模型,其中包含“主动”,“离线”,“在线”等状态。

我有另一个名为Device的模型belongs_toDeviceState

要在设备模型上使用@device.active?@device.offline?等方法,我已经定义了一个动态方法,如下所示:

  DeviceState.all.each do |method|
    define_method((method.name + "?").to_sym) do
        self.device_state.name == method.name
    end
  end

我的问题是,当我尝试在Device模型上创建测试时,不会创建动态方法,因为在测试环境启动时尚未在数据库上填充DeviceState模型。所以当我用工厂女孩创建DeviceState数据时,为时已晚。

我尝试过的一个解决方案是在DeviceState中播种spec_helper,但是当这适用于第一次测试时,由于数据库清理程序删除了数据,因此它不适用于所有其他测试。

克服这些动态定义方法的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

正如大家在评论中指出的那样,你应该根据数据库表使状态列表静态而不是动态。

如果您决定将此列表设为静态,请执行以下操作以避免每次添加状态时都必须编写新方法。

应用\模型\ devise.rb

class Devise < ActiveRecord::Base
  ...
  extend EnumFieldUtil
  enum_field :devise_state, %w[active offline online]
  ...
end

使用您可以在lib文件夹中定义的实用程序方法,以便在必要时可以在其他模型中重复使用

<强> LIB \ enum_field_util.rb

module EnumFieldUtil
  def enum_field(field, allowed_values)
    allowed_values.each do |value|
      class_eval %Q{
        define_method("is_#{value}?") { self.#{field} == '#{value}' }
      }
    end

    class_eval %Q{
      validates_inclusion_of :#{field}, :in => #{allowed_values}, :message => "{{value}} must be in #{allowed_values.join ','}"
    }
  end
end

Ryan Bate's Rail Casts on state machines启发