Rails 4 Minitest тестирует виртуальные атрибуты

Итак, у меня есть класс TimeBank, который обновляется и получает два новых виртуальных атрибута, которые будут манипулировать двумя другими существующими атрибутами (столбцами БД).

class TimeBank < ActiveRecord::Base
  # validations, consts, few other methods omitted for brevity

  def date_worked
    @date_worked ||= self.start.to_date
  rescue
    Date.current
  end

  def date_worked=(date_worked_val)
    self.attributes['date_worked'] = date_worked_val
  end

  def hours_worked
    @hours_worked ||= hours
  rescue NoMethodError
    nil
  end

  def hours_worked=(hours_worked_val)
    self.attributes['hours_worked'] = hours_worked_val
  end

  def hours
    if attributes["hours"]
      read_attribute(:hours).to_f 
    else
      ((finish - start)/1.hour).to_f
    end
  rescue NoMethodError
    0.0
  end

  # other methods omitted for brevity...
end

При использовании приложения все работает нормально. При выполнении тестов каждый раз, когда я создаю экземпляр TimeBank, я получаю только результаты операторов rescue выше, а именно сегодняшнюю дату для date_worked и 0.0 для hours_worked. Сеттеры кажутся невосприимчивыми, как будто они ничего не делают (во время тестов).

Я также определил сеттеры для использования write_attribute(:date_worked, 'SOMEVAL'), и хотя это работает в приложении, для тестов я получаю такие ошибки, как

ActiveModel::MissingAttributeError: can't write unknown attribute hours_worked'
app/models/time_bank.rb:110:in `hours_worked='

Пример теста будет следующим:

describe "virtual attributes test" do
  subject { TimeBank.new({member: @gus, admin_id: @addy.id, date_worked: Date.yesterday, hours_worked: 2.5, time_type: "store_shift", approved: true}) }

  it "tests setter callbacks" do
    subject.date_worked.must_equal Date.yesterday
    subject.hours_worked.must_equal 2.5
  end
end

Оба утверждения всегда терпят неудачу, так как они получают сегодняшнюю дату и 0.0 («значения по умолчанию», как указано в геттерах). Если я устанавливаю атрибуты в строке непосредственно перед тестами, это все равно не действует.

Я не уверен, что я делаю неправильно. Я хотел бы написать тесты для этих двух виртуальных атрибутов, но любая установка их значений, похоже, не имеет никакого эффекта. Я не уверен, почему он не работает в тестах, но отлично работает в приложении. Тот же код работает, как и ожидалось, в контроллерах приложений. Может ли кто-нибудь помочь мне понять, почему?


person Todd    schedule 13.08.2015    source источник


Ответы (1)


Проблема заключается в методах установки. Вместо того, чтобы присваивать что-то self.attributes["virtual_attribute"], необходимо установить и вернуть переменную экземпляра, например:

def virtual_attribute=(virtual_attr_value)
  @virtual_attribute = virtual_attr_value
end

Итак, для моего примера мне понадобилось:

def hours_worked=(hours_worked_val)
  @hours_worked = hours_worked_val
end

И приложение, и мои тесты getter/setter в minitest теперь ведут себя так, как ожидалось.

person Todd    schedule 17.08.2015