Фабрики Rspec / FactoryBot не запускаются after_initialize при создании нового экземпляра в моем приложении rails - PullRequest
1 голос
/ 13 мая 2019

У меня есть некоторые модели, использующие хук after_initialize, например, для установки загрузки атрибутов по умолчанию и других вещей:

after_initialize do |some_model|
  initializer(some_model)
end

def initializer(some_model)
  #... loads of pre-processing
end

Все это отлично работает в разработке и производстве, однако в моем FactoryBot иТесты rspec этот хук не работает.У меня есть фабрика, которая выглядит следующим образом:

FactoryBot.define do
  factory :some_model do
    some_number { 1 }
    is_it_something { false }
    account { create(:user).accounts.first }
  end
end

Но мои тесты выглядят так:

some_model = create(:some_model)
some_model.initializer(some_model)

Проблема в том, что мне приходится звонить initializer отдельно послесоздание модели FactoryBot.Это вызывает всевозможные проблемы, потому что create() запускает проверки создания, и они терпят неудачу, потому что инициализатор не запускается.

Как я могу заставить FactoryBot запускать after_initialize при создании нового экземпляра?

Спасибо.

(Возможно, здесь у меня неправильная терминология, поэтому, пожалуйста, поправьте меня, если у меня есть.)

Ответы [ 2 ]

1 голос
/ 15 мая 2019

Вы можете использовать обратный вызов after(:build) фабрики для вызова инициализатора, так как factorybot устанавливает атрибуты после инициализации.

FactoryBot.define do
  factory :some_model do
    some_number { 1 }
    is_it_something { false }
    account { create(:user).accounts.first }
    after(:build) do |some_model|
      some_model.initializer(some_model)
    end
  end
end

таким образом, вам не нужно вызывать его каждый раз, когда вы создаете новый объект с фабрики

В любом случае, этот initializer метод выглядит как запах кода. Я не уверен, что он делает, но, возможно, есть лучший способ сделать это, который также предотвращает эту проблему.

0 голосов
/ 15 мая 2019

FactoryBot вызывает сеттеры для атрибутов, а не конструктора, поэтому build :some_model, some_attribute: 123, other_attribute: :foo фактически эквивалентно:

SomeModel.new.tap{|m|
  m.some_attribute = 123
  m.other_attribute = :foo
}

Таким образом инициализатор вызывается для пустого объекта и только после этого все остальные атрибуты получаютset.

Когда вам нужно установить некоторые атрибуты, которые зависят от других - я бы выбрал пользовательские сеттеры, такие как

def some_other_attribute=(val)
  self.some_attribute = calculate(val)
  super
end

или сделал бы это в before_validation

...