Ожидаемое поведение FactoryBot

#ruby-on-rails #testing #rspec #factory-bot

#ruby-on-rails #тестирование #rspec #завод-бот

Вопрос:

Я тестирую задачу rake — update_city_status_for_users :

 task update_city_status_for_users: :environment do
    User.update_city_statuses do |user, new_status|
        # does something
    end
end 
  

Метод User.update_city_statuses :

 def self.update_city_statuses(amp;block)
    users_ids = Journey.valid.where.not(user_id: nil).pluck(:user_id) # Only journeys (valid) for route 1
    users_with_journeys = self.where(id: users_ids)

    Rails.logger.info "Only update users with at least one journey: #{users_with_journeys.count} users to update."

    ActiveRecord::Base.transaction do
      users_with_journeys.each do |u|
            new_status = u.new_status? 
            if new_status != nil
                begin
                    u.update!(city_status: new_status)
                    yield(u,new_status) if block_given?
                rescue => exception
                    Rails.logger.error "Exception updating user with id #{u.id}. Exception: " exception.to_s
                end
            end
        end
    end
  end
  

И это тест:

 RSpec.describe do 
    describe "update_city_status_for_users" do
        it 'updates users with their corespondent new city status: from nil to "Venice"' do

            user = user_with_journeys(5, "Venice")
            city_status_before_task = user.city_status

            BicycleIsland::Application.load_tasks
            Rake::Task['update_city_status_for_users'].invoke

            expect(city_status_before_task).to eq nil
            expect(user.city_status).to be_an_instance_of CityStatus
            expect(user.city_status.city).to eq "Venice"
        end
    end
end
  

user_with_journeys определяется, где находятся пользовательские фабрики, и в основном он создает пользователя с 5 путешествиями.

После вызова задачи внутри теста я проверяю пользовательскую переменную (созданную на заводе):

 user.city_status 
# nil
  

Однако, когда я извлекаю пользователя из базы данных, связь была установлена, и city_status не равен нулю:

 User.find(user.id).city_status 
# #<CityStatus id: 6, level: 6, city: "Venice", distance: 1730, created_at: "2020-11-18 17:11:32", updated_at: "2020-11-18 17:11:32", image_file_name: "Venice-1000.png">
  

Оба пользователя одинаковы:

 User.find(user.id) == user
# true
  

Однако city_status не связан при непосредственном вызове фабрики. Это не то поведение, которого я ожидал. Я ожидал бы продолжения сделанных обновлений и ассоциаций.

Я, наверное, что-то упускаю? Может ли кто-нибудь помочь мне указать на это?

Спасибо!

Ответ №1:

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

 user.reload
  

перед вашими утверждениями обновите объект последними значениями из базы данных.

Комментарии:

1. Однако, если я определяю user как let(:user) вне примера user.reload не работает. Есть ли шанс, что вы знаете причину? Спасибо.