首页 > 解决方案 > Rspec : 存根 ActiveStorage 下载方法

问题描述

我在一个系统上工作,该系统使用 ActiveStorage 在 S3 上存储缓存数据,然后再将其用于其他用途。在我的规范中,我想存根这个文件的下载方法,并加载一个特定的文件以进行测试。

allow(user.cached_data).to receive(:download)
                       .and_return(read_json_file('sample_data.json'))

read_json_file是一个规范助手,File.read然后JSON.parse是一个数据文件。)

我收到此错误:

#<ActiveStorage::Attached::One:0x00007f9304a934d8 @name="cached_data", 
@record=#<User id: 4, name: "Bob", email: "bob@email.com",
created_at: "2019-08-22 09:11:16", updated_at: "2019-08-22 09:11:16">,
@dependent=:purge_later> does not implement: download

我不明白,文档清楚地说这个对象应该实现下载。

编辑

正如JigneshStephen所建议的那样,我尝试了这个:

allow(user.cached_data.blob).to receive(:download)
                            .and_return(read_json_file('sample_data.json'))

我收到以下错误:

Module::DelegationError:
       blob delegated to attachment, but attachment is nil

user由 FactoryBot 生成,所以我目前正在尝试将我的cached_data示例文件附加到该对象。

我的工厂是这样的:

FactoryBot.define do
  factory :user
    name { 'Robert' }
    email  { 'robert@email.com' }

    after(:build) do |user|
      user.cached_data.attach(io: File.open("spec/support/sample_data.json"), filename: 'sample.json', content_type: 'application/json')
    end
  end
end

但是当我将该after build块添加到工厂时,我收到以下错误:

ActiveRecord::LockWaitTimeout:
       Mysql2::Error::TimeoutError: Lock wait timeout exceeded

也许这是另一个 Stackoverflow 问题。

标签: ruby-on-railsrspecstubrails-activestorage

解决方案


正如其他人在评论中指出的那样,#download是在ActiveStorage::Blob类上实现的,而不是ActiveStorage::Attached::One. 您可以使用以下内容下载该文件:

if user.cached_data.attached?
  user.cached_data.blob.download
end

我添加了检查以确保cached_data已附加,因为blob代表附件并且如果未附加将失败。

这是#download 的文档


推荐阅读