Действительно медленное тестирование с загрузкой файлов

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


Я работал без проверок и использовал возможность запускать мои тесты rspec примерно за 140 секунд, но поскольку теперь я проверяю присутствие :display_pic, мне пришлось добавлять реальные файлы в мой проект factory. Это увеличило его до 240 секунд! 140 был уже на тяжелой стороне, это просто безумие.

Так, страница github на носителе поддерживает настройку Factory Девушка:

FactoryGirl.define do
  factory :project do
    display_pic { File.open(File.join(Rails.root, 'spec', 'support', 'projects', 'display_pics', 'test.jpg')) }
  end
end

Я сделал выше test.jpg только пустой текстовый файл, поэтому его по существу как можно меньше файла.

Я также следил за рекомендацией операторской волны для настройки тестирования:

CarrierWave.configure do |config|
  config.storage = :file
  config.enable_processing = false
end

Ответ 1

С проверкой того факта, что всегда создается экземпляр, к которому обращается атрибут display_pic, и код внутри скобок

{ File.open(File.join(Rails.root, 'spec', 'support', 'projects', 'display_pics', 'test.jpg')) } 

будет выполняться (выполняется лениво). Это вызывает разницу во времени.

Опция, чтобы избежать этого, - установить to_create для определения factory, что я не рекомендую:

FactoryGirl.define do
  factory :project do
    display_pic { File.open(File.join(Rails.root, 'spec', 'support', 'projects', 'display_pics', 'test.jpg')) }

    to_create do |instance|
      instance.save!(:validate => false)
    end 
  end
end

Ответ 2

Сохраняются ли ваши загрузки локально или они отправляются в облачный сервис, такой как S3? Если последнее, возможно, это то, что убивает вашу тестовую производительность.

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

Обновление: Что касается ответа Джефферсона Гирао, я использовал трюк, чтобы избежать открытия тестового файла и вместо этого использовать StringIO для имитации тестовых файлов для factory цели. Это лучше работает, поскольку позволяет избежать доступа к диску:

def test_file_stream(filename = 'test.jpg', mime_type='image/jpg', content = '')
  StringIO.new(content).tap do |s|
    s.content_type = mime_type
    s.original_filename = filename
  end
end

Ответ 3

С вдохновением @jeffersongirao и @Вольфрам Арнольд:

FactoryGirl.define do
  sequence(:image) do |n|
    {
      tempfile: StringIO.new('{・㉨・}'),
      filename: "#{n}.jpeg",
      content_type: 'image/jpeg'
    }
  end

  factory :user do
    avatar { generate(:image) }
  end
end

Два ключевых момента:

  • Устройства загрузки CarrierWave могут иметь смысл целого ряда вещей. Они делают это, обертывая то, что они получают в CarrierWave::SanitizedFile. Одна из вещей, которые он может принять, - это хэш, как здесь.

  • CarrierWave::SanitizedFile заботится о том, пустой ли файл. Я слишком долго размышлял, почему он не примет мой StringIO.new. Здесь нужно что-то там, но все равно. Я дал ему коалу.

Ответ 4

Вероятно, вы уже это рассматривали, но это 100-секундное замедление, связанное с загрузкой одного файла? Если это совокупность по всем тестам, должен быть способ структурировать их так, чтобы у вас был один тест (или несколько), который проверяет наличие файла, а остальное время вы просто издеваетесь над ним.

Ответ 5

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

DUMMY_IMAGE = File.open(File.join(Rails.root, 'spec', 'support', 'projects', 'display_pics', 'test.jpg'))
FactoryGirl.define do
  factory :project do
    display_pic DUMMY_IMAGE
  end
end

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

Мне не нравится решение, которое требует от вас не проверять модель. Я думаю, это похоже на ответ StringIO Вольфрама Арнольда, хотя я думаю, что этот способ немного легче понять.