2013-09-16 6 views
0

У меня есть модель под названием DeviceState, которая содержит такие состояния, как «активный», «автономный», «онлайн».Как протестировать динамически определенные методы, основанные на другой модели

У меня есть другая модель под названием Device, которая belongs_to - DeviceState.

Чтобы иметь такие методы, как @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, однако в то время как это сработало для первого теста, оно не сработало для остальных, поскольку очиститель базы данных удалил данные.

Что было бы лучшим способом преодолеть эти динамически определенные методы?

+0

Вы определенно не должны определять эти методы динамически. Это огромный запах кода. – meagar

+0

Действительно? Но тогда каждый раз, когда мне нужно будет добавить новое состояние, мне придется добавлять новые методы в модель устройства. Теперь я просто добавляю его в модель DeviceState, и все работает. Это была идея этого. Не хорошо? – bymannan

+0

Модель 'Устройство' загружается, когда ваш сервер запускается и не перезагружается снова (я имею в виду в ПРОИЗВОДСТВЕ), и при добавлении нового состояния вы не получите новый определенный метод. Будьте осторожны, пожалуйста. Начните свое приложение в режиме производства и протестируйте его! – gotva

ответ

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

Смежные вопросы