Как протестировать условную проверку с помощью rspec-rails 3.0.0 и shoulda-matchers 2.5.0

Я запускаю приложение Rails 4 с rspec-rails 3.0.0 и shoulda-matchers 2.5.0, и у меня есть модель событий, которая имеет некоторые условные проверки, например:

class Event < ActiveRecord::Base
  validates :name, :location, :time, :city, :zipcode, :user, :state, presence: true
  validates :post_text, presence: true, if: :happened?
  validates :pre_text, presence: true, unless: :happened?

  belongs_to :community
  belongs_to :user
  belongs_to :state

  def happened?
    (self.time < Time.now) ? true : false
  end
end

Мой event_spec.rb выглядит так:

require 'spec_helper'

describe Event do
  before { @event = FactoryGirl.build(:future_event) }

  subject { @event }

  it { should validate_presence_of(:time) }
  it { should validate_presence_of(:name) }
  it { should validate_presence_of(:location) }
  it { should validate_presence_of(:user) }
  it { should validate_presence_of(:city) }
  it { should validate_presence_of(:state) }
  it { should validate_presence_of(:zipcode) }

  it { should belong_to(:state) }
  it { should belong_to(:user) }

  it 'has pre_text if future event' do
     expect(FactoryGirl.create(:future_event)).to be_valid
  end

  it 'has post_text if past event' do
    expect(FactoryGirl.create(:past_event)).to be_valid
  end
end

Но когда я запускаю тесты, мой блок it { should validate_presence_of(:time) } дает сбой, потому что он продолжает выполнять оставшиеся проверки и выдает исключение для условных проверок, потому что self.time равен нулю. Я реализовал хакерское исправление для этого, проверив time.present? в случившемся? метод. Но может ли кто-нибудь помочь мне понять, как лучше всего тестировать условные проверки, требующие наличия другого поля?


person Tyler    schedule 03.03.2014    source источник


Ответы (3)


Да, к сожалению, другого выхода нет. Дело в том, что time технически разрешено быть равным нулю до того, как вы сохраните запись о событии, поэтому, если вы вызовете #happened? до того, как будет установлено значение time, оно вызовет исключение. Так что, если бы я написал этот код, лично я был бы в порядке с галочкой #случилось?, потому что это случай, который вам все равно придется обрабатывать (независимо от вероятности того, что это действительно произойдет).

person Elliot Winkler    schedule 03.03.2014

Это определенно поздно, но для других, которые ищут решение. Я нашел эффективный способ сделать это:

context "if happened" do
  before { allow(subject).to receive(:happened?).and_return(true) }
  it { is_expected.to validate_presence_of(:time) }
end

надеюсь, это поможет

person El'Magnifico    schedule 26.07.2015
comment
Это правильный ответ, и его следует принять. - person Midwire; 17.06.2016
comment
Мне это не кажется правильным. Вы издеваетесь над чем-то, а затем ожидаете, что результат будет правдой. Конечно, это будет правдой, вы так издевались. Вы не проверяете логику, вы проверяете макет, верно? - person emptywalls; 13.07.2016
comment
@emptywalls, вы понимаете контекст вопроса ОП? Он не тестирует метод :happened?. Он хочет проверить подтверждение присутствия времени. Время в этом случае присутствует только тогда, когда событие произошло. Чтобы ограничить ожидание проверочного теста моментом, когда событие произошло (когда :happened? возвращает true). Нужно смоделировать happened?, чтобы вернуть true, чтобы validate_presence_of(:time) вызывался только с этим условием. Итак, я только издевался над условием, что проверка зависит от того, что именно нужно OP. - person El'Magnifico; 13.07.2016

Просто небольшой совет:

def happened?
  (self.time < Time.now) ? true : false
end

такой же как

def happened?
  self.time < Time.now
end
person franciscomxs    schedule 08.10.2014