How to test conditional validation with rspec-rails 3.0.0 and shoulda-matchers 2.5.0

大憨熊 提交于 2019-12-10 16:44:56

问题


I'm running a Rails 4 app with rspec-rails 3.0.0 and shoulda-matchers 2.5.0, and I've got an Event model that has some conditional validations like so:

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

My event_spec.rb looks like:

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

But when I run the tests, my it { should validate_presence_of(:time) } block fails because it continues to run the remaining validations and throws an exception on the conditional validations because self.time is nil. I have implemented a hacky fix for this by checking time.present? in the happened? method. But can anyone help me understand what the best method for testing conditional validations that require the presence of another field would be?


回答1:


Yeah, unfortunately there isn't another way. The fact is that time is technically allowed to be nil before you save your Event record, so if you happen to call #happened? before time gets set, it will raise an exception. So if I wrote this code I would personally be okay with placing a check in #happened?, because it's a case you would need to handle anyway (regardless of the chance this will actually happen).




回答2:


This is definitely coming late, but for others searching for a solution. I found an effective way of doing this:

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

I hope this helps




回答3:


Just a small tip:

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

is the same as

def happened?
  self.time < Time.now
end


来源:https://stackoverflow.com/questions/22156073/how-to-test-conditional-validation-with-rspec-rails-3-0-0-and-shoulda-matchers-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!