【问题标题】:Really slow testing with file uploads文件上传测试真的很慢
【发布时间】:2015-04-01 22:14:03
【问题描述】:

我刚刚将载波图像的验证添加到模型中,现在测试运行速度非常慢。我怎样才能加快这个过程?我觉得一定有更好的方法。


我一直在没有验证的情况下运行,并且过去能够在大约 140 秒内运行我的 rspec 测试,但由于我现在验证 :display_pic 的存在,我不得不将真实文件上传添加到我的项目工厂。这已将其提高到 240 秒! 140已经很重了,这太疯狂了。

This is how the carrierwave github page recommends setting up Factory Girl:

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

【问题讨论】:

    标签: ruby-on-rails rspec carrierwave factory-bot


    【解决方案1】:

    您的上传内容是存储在本地还是将它们发送到 S3 之类的云服务?如果是后者,那可能会影响您的测试性能。

    对于测试,模拟任何外部依赖项始终是一个好习惯。如果这是您的问题,您应该使用工具来模拟连接。我认为fog gem 内置了对此的支持。

    更新:Regarding the answer by Jefferson Girao,我使用了一个技巧来避免打开测试文件,而是使用 StringIO 来模拟测试文件以用于工厂目的。这表现得更好,因为它避免了磁盘访问:

    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
    

    【讨论】:

    • 是的,谢谢,这已经完成config.storage = :file 载波中的行配置块力,在生产中它被设置为雾
    • 有趣。那我就猜不透了。对不起。
    • 这发生了(140 秒的差异)b/c,因为工厂女孩懒洋洋地评估它以前从未执行过。现在,当您运行验证时,将始终访问该属性。
    • 谢谢你,太棒了!
    • 这对我不起作用。 StringIO 既没有“content_type”也没有“original_filename”属性。
    【解决方案2】:

    现在总是进行验证,即创建一个实例,访问属性 display_pic 并且括号内的代码

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

    将被执行(它被延迟执行)。这导致了时间上的差异。

    避免这种情况的一个选项是为工厂定义设置我不推荐的 to_create:

    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
    

    【讨论】:

    • 我不希望绕过验证。在回形针中,您可以用字符串填充 pic 字段,我希望能有类似的东西。
    • 感谢您的回复,我明白这是合乎逻辑的,加载时间会更长,但是加载时间对于我的测试目的来说太长了,希望有办法将其最小化。
    • 这是迄今为止我见过的最好的解决方案,而且很有效,谢谢
    • 我的错,当赏金到期时,我是 MIA,除非有人想出一种方法来模拟使用 carrierwave 上传文件的方法,否则我只会把这 100 传给你。
    【解决方案3】:

    灵感来自@jeffersongirao@Wolfram Arnold

    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
    

    这里有两个关键:

    1. CarrierWave 的上传设置器可以理解很多事情。他们通过将获得的内容包装在CarrierWave::SanitizedFile 中来做到这一点。它可以采用的其中一件事是哈希,就像这里一样。

    2. CarrierWave::SanitizedFile 关心文件是否为空。我花了太长时间想知道为什么它不接受我的StringIO.new。它需要在那里有一些东西,但它不在乎是什么。我给了它一只考拉。

    【讨论】:

      【解决方案4】:

      您可能已经考虑过这一点,但 100 秒的减速与 单个 文件上传有关吗?如果它是所有测试的聚合,则必须有一种方法来构建它们,以便您有一个(或几个)验证文件存在的测试,而其余时间您只需将其模拟出来。

      【讨论】:

      • 您会提出与 Jefferson Girao 不同的建议还是同意?
      【解决方案5】:

      我刚刚遇到了这个问题,通过将文件存储在内存中而不是让工厂在每次测试时都从磁盘读取图像可能有助于解决这个问题。我正在使用类似以下的东西。

      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% 的时间,但是我的测试套件是安静的变量,所以我不能绝对确定。无论如何,如果有人遇到这个问题,请考虑一下。

      我不太喜欢要求您不验证模型的解决方案。我想这类似于 Wolfram Arnold 的 StringIO 答案,尽管我认为这种方式更容易理解。

      【讨论】:

        猜你喜欢
        • 2010-12-19
        • 1970-01-01
        • 2023-04-06
        • 2011-11-29
        • 1970-01-01
        • 2014-06-13
        • 1970-01-01
        • 2018-11-26
        • 2011-12-12
        相关资源
        最近更新 更多