使用 RSpec 测试自定义验证方法

Testing custom validation method with RSpec

我尝试测试检查活动时间重叠的验证方法。

共有三个工厂(其中两个继承自activity)。

工厂:

activities.rb

FactoryGirl.define do
    factory :activity do
      name 'Fit Girls'
      description { Faker::Lorem.sentence(3, true, 4) }
      active true
      day_of_week 'Thusday'
      start_on '12:00'
      end_on '13:00'
      pool_zone 'B'
      max_people { Faker::Number.number(2) }
      association :person, factory: :trainer

   factory :first do
     name 'Swim Cycle'
     description 'Activity with water bicycles.'
     active true
     day_of_week 'Thusday'
     start_on '11:30'
     end_on '12:30'
  end

   factory :second do
     name 'Aqua Crossfit'
     description 'Water crossfit for evereyone.'
     active true
     day_of_week 'Thusday'
     start_on '12:40'
     end_on '13:40'
     pool_zone 'C'
     max_people '30'
   end
   end
 end

在相同 day_of_week(activity.day_of_week == first.day_of_week)、相同 pool_zone(activity.pool_zone == first.pool_zone) 和时间重叠。

验证方法:

  def not_overlapping_activity
    overlapping_activity = Activity.where(day_of_week: day_of_week)
                                   .where(pool_zone: pool_zone)

    activities = Activity.where(id: id)
    if activities.blank?
      overlapping_activity.each do |oa|
        if (start_on...end_on).overlaps?(oa.start_on...oa.end_on)
          errors.add(:base, "In this time and pool_zone is another activity.")
        end
      end
    else
      overlapping_activity.where('id != :id', id: id).each do |oa|
        if (start_on...end_on).overlaps?(oa.start_on...oa.end_on)
          errors.add(:base, "In this time and pool_zone is another activity.")
        end
      end
    end
  end

我写了rspec测试,不幸的是检查无效。

describe Activity, 'methods' do
  subject { Activity }
 describe '#not_overlapping_activity' do
    let(:activity) { create(:activity) }
    let(:first) { create(:first) }

      it 'should have a valid factory' do
        expect(create(:activity).errors).to be_empty
      end
      it 'should have a valid factory' do
        expect(create(:first).errors).to be_empty
      end

    context 'when day_of_week, pool_zone are same and times overlap' do
      it 'raises an error that times overlap' do
        expect(activity.valid?).to be_truthy
        expect(first.valid?).to be_falsey
        expect(first.errors[:base].size).to eq 1
      end
    end
  end
end

Return:

Failure/Error: expect(first.valid?).to be_falsey

       expected: falsey value
            got: true

我不明白为什么它是真的。 first create(:activity) 应该是正确的,但next不应该被执行(重叠)。 我尝试在 expect(first.valid?... 之前添加 expect(activity.valid?).to be truthy,但抛出另一个错误 ActiveRecord::RecordInvalid。有人可以修复我的测试吗?我是使用 RSpec.

创建测试的新手

更新: 我的问题的解决方案不是 create :first in test 而是 build。 let(:first) { build(:first) }

这一行独立

let(:activity) { create(:activity) }

不会创建 activity。它仅在实际调用 activity 时创建一个 activity。因此,您必须在 运行 测试之前的某处调用 activity

有几种方法可以做到这一点,例如前块:

before { activity }

或者您可以使用 let! 而不是 let.