You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RSpec中配置Fog Mock测试CarrierWave Google存储上传方法

CarrierWave 对接Fog Mock测试全流程(GCS存储场景)

一、前置依赖安装

  • 先在项目Gemfile中声明所需依赖,执行bundle install完成安装
# Gemfile
gem 'carrierwave'
gem 'fog-google'
gem 'minitest' # Ruby生态通用轻量测试框架,新手友好

*注意:你提供的原始代码存在两处语法/逻辑错误,先修正为可运行版本:

  1. store_dir方法直接写when分支,缺少case判断头部
  2. store_dir中调用file.getpath不存在,关联模型属性通过model.xxx调用

修正后的上传器与模型代码如下:

# test_uploader.rb
class TestUploader < CarrierWave::Uploader::Base
  storage :fog

  def fog_credentials
    {
      provider: 'google',
      google_project: 'my project',
      google_json_key_location: 'myCredentialFile.json'
    }
  end

  def fog_provider
    'fog/google'
  end

  def fog_directory
    'test-bucket-name'
  end

  def store_dir
    case file.content_type
    when %r{application/.*}, /file/
      "#{model.id}/file"
    when %r{audio/.*}
      "#{model.id}/audio"
    else
      raise "Invalid file type"
    end
  end
end
# test_model.rb
class TestModel
  # 非Rails环境需要手动引入上传器挂载方法
  extend CarrierWave::Mount
  # 声明实例属性,对应模型主键和上传字段
  attr_accessor :id, :images
  mount_uploader :images, TestUploader

  def initialize(id = 1)
    @id = id
  end
end

二、测试环境Mock配置

Fog原生内置mock模式,所有存储操作在内存中完成,不会发起真实云服务请求,也不会产生费用。
在项目根目录新建test文件夹,创建测试初始化文件test_helper.rb:

# test/test_helper.rb
require 'minitest/autorun'
require 'carrierwave'
require 'fog/google'
require_relative '../test_uploader'
require_relative '../test_model'

# 核心开关:开启Fog全局mock模式
Fog.mock!

# 预创建mock环境下的存储桶,避免上传时报桶不存在错误
Fog::Storage.new(
  provider: 'google',
  google_project: 'test-project',
  # mock模式下不需要真实密钥,填合法格式的字符串即可
  google_json_key_string: '{"type":"service_account"}'
).put_bucket('test-bucket-name')

# 配置CarrierWave测试临时目录,避免污染本地文件
CarrierWave.configure do |config|
  config.root = File.expand_path('../tmp_test', __dir__)
  config.cache_dir = 'cache'
end

三、单元测试用例编写

在test目录下创建测试文件test_uploader_test.rb,覆盖核心上传逻辑:

# test/test_uploader_test.rb
require_relative './test_helper'

class TestUploaderTest < Minitest::Test
  def setup
    # 每个测试用例执行前初始化干净的测试数据
    @model = TestModel.new(1001)
    # 生成临时测试音频文件
    File.write(File.join(CarrierWave.root, 'test.mp3'), 'fake audio content')
    @audio_file = File.open(File.join(CarrierWave.root, 'test.mp3'))
    # 生成临时测试普通文件
    File.write(File.join(CarrierWave.root, 'test.bin'), 'fake file content')
    @regular_file = File.open(File.join(CarrierWave.root, 'test.bin'))
  end

  def teardown
    # 每个用例执行后清空mock数据和临时文件
    Fog::Mock.reset
    FileUtils.rm_rf(CarrierWave.root)
  end

  def test_audio_file_upload_path
    @model.images = @audio_file
    # 非Rails环境需要手动触发存储,Rails/ActiveRecord模型保存时会自动触发
    @model.images.store!
    # 校验存储路径符合规则
    assert_match %r{1001/audio/}, @model.images.path
    # 校验文件在mock存储中存在
    assert @model.images.exists?
    # 校验文件内容正确
    assert_equal 'fake audio content', @model.images.file.read
  end

  def test_regular_file_upload_path
    @model.images = @regular_file
    @model.images.store!
    assert_match %r{1001/file/}, @model.images.path
    assert @model.images.exists?
  end

  def test_invalid_file_raise_error
    File.write(File.join(CarrierWave.root, 'test.txt'), 'invalid content')
    invalid_file = File.open(File.join(CarrierWave.root, 'test.txt'))
    @model.images = invalid_file
    assert_raises(RuntimeError, "Invalid file type") do
      @model.images.store!
    end
  end
end

四、测试执行与验证

在项目根目录执行测试命令:

ruby test/test_uploader_test.rb

预期结果:

  • 执行过程无外网请求,无GCS权限报错
  • 3个测试用例全部通过
  • 本地临时目录tmp_test在测试结束后自动清空

如果你是在Rails项目中使用,不需要手动引入CarrierWave::Mount,也不需要手动调用store!,ActiveRecord的保存回调会自动触发上传逻辑,Fog mock配置直接写到config/environments/test.rb中即可。

内容的提问来源于stack exchange,提问作者sagar verma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 19:51:45