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

为何单独运行Active Storage模型测试时会挂起?

问题描述

我安装了以下gem用于Active Storage的验证和测试:

gem 'active_storage_validations'
gem 'shoulda-matchers', '~> 6.0'

模型代码(app/models/asset.rb)

class Asset < ApplicationRecord
  has_one_attached :portrait

  validates(
    :name,
    presence: true,
    uniqueness: true,
    format: {
      with: /\A[\w\.\-\(\)\+]+\z/s,
      message: 'Only alphanumeric, and _-()+. characters are allowed.' # rubocop:disable Rails/I18nLocaleTexts
    }
  )

  validates(
    :portrait,
    content_type: ['image/png', 'image/jpeg', 'image/svg+xml'],
    dimension: { width: { in: 8..512 }, height: { in: 8..512 } },
    size: { less_than: 250.kilobytes }
  )
end

测试代码(spec/models/asset_spec.rb)

require 'rails_helper'

RSpec.describe Asset do
  subject(:asset) { build(:asset) }

  it { is_expected.to validate_uniqueness_of :name }
  it { is_expected.to allow_value('123-45+a_').for(:name) }
  it { is_expected.not_to allow_value('123=').for(:name) }

  it { is_expected.to validate_size_of(:portrait).less_than(250.kilobytes) }
end

相关配置文件

spec/support/active_storage.rb(已被spec/rails_helper.rb引入)

require 'active_storage_validations/matchers'
require 'ostruct'

RSpec.configure do |config|
  config.include ActiveStorageValidations::Matchers
end

spec/support/shoulda_matchers.rb(已被spec/rails_helper.rb引入)

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end

工厂代码(spec/factories/assets.rb)

FactoryBot.define do
  factory :asset do
    name { "#{Forgery::Internet.user_name}#{Asset.count}" }
    portrait { nil }
  end
end

当前问题

运行全部测试时一切正常,但单独执行rspec spec/models运行模型测试时,测试出现挂起,这是为什么?


问题原因及解决方案

这种挂起通常是因为单独运行模型测试时,Active Storage的依赖服务未被初始化。运行全部测试时,其他测试(如系统测试、请求测试)会触发Active Storage的初始化流程,但单独跑模型测试时该流程被跳过,导致验证器处理附件时卡住。

具体来说,active_storage_validations的validate_size_of匹配器需要模拟附件对象,若Active Storage的底层服务(如测试存储的临时目录、服务配置)未正确初始化,就会引发进程挂起。

可通过以下方法解决:

  1. 手动初始化Active Storage服务
    在spec/support/active_storage.rb中补充初始化逻辑,确保测试套件启动时加载Active Storage服务:

    RSpec.configure do |config|
      config.before(:suite) do
        ActiveStorage::Blob.service = ActiveStorage::Service.configure(:test, Rails.application.config.active_storage)
      end
    end
    
  2. 为工厂提供有效测试附件
    当前工厂中portrait设为nil,验证器无法正常处理空值。可修改工厂生成临时测试图片:

    FactoryBot.define do
      factory :asset do
        name { "#{Forgery::Internet.user_name}#{Asset.count}" }
        portrait { Rack::Test::UploadedFile.new(Rails.root.join('spec/fixtures/files/test_image.png'), 'image/png') }
      end
    end
    

    需提前在spec/fixtures/files/目录下放置一张测试用PNG图片。

  3. 确认测试环境Active Storage配置
    检查config/environments/test.rb,确保使用测试专用存储服务:

    config.active_storage.service = :test
    

单独运行模型测试时,RSpec可能未加载完整的Rails初始化流程,手动触发Active Storage服务初始化即可解决挂起问题。

内容的提问来源于stack exchange,提问作者Chiara Ani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 12:50:15