为何单独运行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的底层服务(如测试存储的临时目录、服务配置)未正确初始化,就会引发进程挂起。
可通过以下方法解决:
手动初始化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为工厂提供有效测试附件
当前工厂中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图片。确认测试环境Active Storage配置
检查config/environments/test.rb,确保使用测试专用存储服务:config.active_storage.service = :test
单独运行模型测试时,RSpec可能未加载完整的Rails初始化流程,手动触发Active Storage服务初始化即可解决挂起问题。
内容的提问来源于stack exchange,提问作者Chiara Ani
相关产品推荐
相关产品推荐

