Заводська дівчина, яка обходить мою перевірку моделі


78

Я використовую Factory Girl для створення двох екземплярів у своїй тесті моделі / одиниці для групи. Я тестую модель, щоб перевірити, що виклик .current повертає лише "поточні" групи відповідно до атрибуту закінчення, як зазначено нижче ...

  describe ".current" do
    let!(:current_group) { FactoryGirl.create(:group, :expiry => Time.now + 1.week) }
    let!(:expired_group) { FactoryGirl.create(:group, :expiry => Time.now - 3.days) }

    specify { Group.current.should == [current_group] }
  end

Моя проблема полягає в тому, що я перевірив модель, яка перевіряє термін дії нової групи після сьогоднішньої дати. Це спричиняє помилку перевірки нижче.

  1) Group.current 
     Failure/Error: let!(:expired_group) { FactoryGirl.create(:group, :expiry => Time.now - 3.days) }
     ActiveRecord::RecordInvalid:
       Validation failed: Expiry is before todays date

Чи є спосіб примусово створити Групу або обійти перевірку при створенні за допомогою Factory Girl?

Відповіді:


91

Це не дуже специфічно для FactoryGirl, але ви завжди можете обійти перевірку при збереженні моделей за допомогою save(:validate => false):

describe ".current" do
  let!(:current_group) { FactoryGirl.create(:group) }
  let!(:old_group) {
    g = FactoryGirl.build(:group, :expiry => Time.now - 3.days)
    g.save(:validate => false)
    g
  }

  specify { Group.current.should == [current_group] }
end

Дивіться відповідь Джейсона Денні нижче для кращого рішення.
Девід Хемпі,

1
з 1.9.1 ви можете це зробитиg.tap { |g| g.save(validate: false) }
yefrem

58

Я віддаю перевагу цьому рішенню з https://github.com/thoughtbot/factory_girl/issues/578 .

Усередині заводу:

to_create {|instance| instance.save(validate: false) }

РЕДАГУВАТИ:

Як згадувалося у посиланні, а також у коментарях / рішеннях інших користувачів, ви, швидше за все, захочете обернути це в блок ознак, щоб уникнути плутанини / проблем в інших місцях ваших тестів; наприклад, коли ви тестуєте свої перевірки.


5
Це набагато елегантніше рішення, ніж прийняте.
Kyle Heironimus

5
Майте на увазі, що якби ви робили це для своєї загальнозаводської фабрики, ви б пропускали перевірки КОЖНОГО разу, коли створювали цю фабрику. Напевно, найкраще використовувати цю техніку лише на підзаводі (або за ознакою).
tgf

Ви майже напевно захочете поставити це в якості риси. Дивіться відповідь Тіма Скотта нижче.
Девід Хемпі,

41

Погано пропускати перевірку за замовчуванням на заводі. Деякі волосся будуть вирвані, виявивши це.

Думаю, найкращий спосіб:

trait :skip_validate do
  to_create {|instance| instance.save(validate: false)}
end

Тоді у вашому тесті:

create(:group, :skip_validate, expiry: Time.now + 1.week)

1
це найкращий спосіб вирішити цю проблему!
hatenine

Чи є спосіб застосувати це на всіх заводах?
адаам

завжди дивно знайти ці маленькі фрагменти у вже існуючих базах кодів. Ви знаєте, що нинішній або колишній колега знайшов цю точну відповідь раніше.
Ділан Пірс,

7

У цьому конкретному випадку перевірки датою baesd ви також можете використовувати самоцвіт timecop, щоб тимчасово змінити час, щоб імітувати старий запис, створений у минулому.



6

Не найкраще пропускати всі перевірки цієї моделі.

створити spec/factories/traits.rbфайл.

FactoryBot.define do
  trait :skip_validate do
    to_create { |instance| instance.save(validate: false) }
  end
end

виправити специфікацію

describe ".current" do
  let!(:current_group) { FactoryGirl.create(:group, :skip_validate, :expiry => Time.now + 1.week) }
  let!(:expired_group) { FactoryGirl.create(:group, :skip_validate, :expiry => Time.now - 3.days) }

  specify { Group.current.should == [current_group] }
end

1

Залежно від вашого сценарію ви можете змінити перевірку, яка відбуватиметься лише під час оновлення. Приклад::validates :expire_date, :presence => true, :on => [:update ]


1

Ваші заводи повинні створювати дійсні об'єкти за замовчуванням. Я виявив, що перехідні атрибути можна використовувати для додавання умовної логіки, як це:

transient do
  skip_validations false
end

before :create do |instance, evaluator|
  instance.save(validate: false) if evaluator.skip_validations
end

У вашому тесті:

create(:group, skip_validations: true)

0

Або ви можете використовувати FactoryBotі Timecopте, і інше:

trait :expired do
  transient do
    travel_backward_to { 2.days.ago }
  end
  before(:create) do |_instance, evaluator|
    Timecop.travel(evaluator.travel_backward_to)
  end
  after(:create) do
    Timecop.return
  end
end

let!(:expired_group) { FactoryGirl.create(:group, :expired, travel_backward_to: 5.days.ago, expiry: Time.now - 3.days) }

Редагувати : Не оновлювати цю подію після створення або перевірки не вдасться.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.