Rails 7.1+RSpec测试因Active Storage附件冻结求助
问题:RSpec测试因ActiveStorage附件冻结并抛出反序列化错误
环境信息
- Ruby 3.3.0
- Rails 7.1.3.2
- factory_bot 6.4.6
- mini_magick 4.12.0
- rspec-rails 6.1.2
- OSX
问题现象
浏览器中所有功能运行正常,但执行涉及Song模型的RSpec测试时,进程大概率冻结(Intel处理器90%概率、ARM处理器60%概率),测试输出停滞在:
Song associations is expected to belong to album required: true validates is expected to validate that :artist_name cannot be empty/falsy #ordered when have only one disc
仅当FactoryBot中为Album的cover属性添加附件时触发问题,移除附件则测试正常。测试日志中出现错误:
Error performing ActiveStorage::AnalyzeJob (Job ID: ee23c48f-38ed-4a96-a3f5-a3b11645a028) from Async(default) in 5.02ms: ActiveJob::DeserializationError (Error while trying to deserialize arguments: undefined method `clear' for nil):
相关代码
Album模型
class Album < ApplicationRecord has_one_attached :cover do |attachable| attachable.variant :thumb, resize: '100x100' attachable.variant :medium, resize: '400x400' end # Associations has_many :songs, dependent: :destroy # Validations validates :title, :artist_name, presence: true validates :cover, attached: true end
Song模型
class Song < ApplicationRecord # Attachments has_one_attached :audio # Associations belongs_to :album # Scopes scope :ordered, -> { order(disk_number: :asc, track_number: :asc) } end
Song的RSpec测试
RSpec.describe Song do subject(:song) { create(:song, album:) } let(:album) { create(:album, cover: file_fixture('cover.jpg')) } describe 'associations' do it { expect(song).to belong_to('album') } end describe 'validates' do it do expect(album).to validate_presence_of(:title) expect(album).to validate_presence_of(:artist_name) end end describe '#ordered' do subject(:ordered) { described_class.ordered } context 'when have only one disc' do let(:song1) { create(:song, track_number: 1, album:) } let(:song2) { create(:song, track_number: 2, album:) } it 'returns array with correct ordered songs' do expect(ordered).to eq([song, song2]) end end context 'when you have two disc and the same track number' do let(:song1) { create(:song, track_number: 1, disk_number: 1, album:) } let(:song2) { create(:song, track_number: 1, disk_number: 2, album:) } it 'returns array with ordered by track and disc' do expect(ordered).to eq([song1, song2]) end end end ... end
Album的FactoryBot定义
FactoryBot.define do factory :album do title { 'MyString' } artist_name { 'Artist' } label { 'MyString' } upc { 'MyString' } release_date { '2024-03-24 13:14:12' } cover { File.open('spec/fixtures/cover.jpg') } end end
解决方案思路
强制ActiveStorage任务同步执行
在config/environments/test.rb中配置,避免异步任务引发的序列化问题:config.active_job.queue_adapter = :inline # 或者仅针对ActiveStorage的任务 config.active_storage.queues.analyze = :inline config.active_storage.queues.purge = :inline优化FactoryBot的附件处理
改用Rails提供的fixture_file_upload确保文件对象正确处理:factory :album do # ...其他属性 cover { fixture_file_upload('cover.jpg', 'image/jpeg') } end跳过附件分析任务
在测试环境中禁用ActiveStorage的附件分析,减少测试中的额外操作:# config/environments/test.rb config.active_storage.analyze = false或者在测试中临时跳过:
RSpec.describe Song do before do allow_any_instance_of(ActiveStorage::Blob).to receive(:analyze_later).and_return(nil) end # ...测试内容 end验证MiniMagick依赖
确保OSX上已安装ImageMagick(执行brew install imagemagick),并在Rails控制台验证图片处理是否正常:image = MiniMagick::Image.open('spec/fixtures/cover.jpg') image.resize('100x100')
内容的提问来源于stack exchange,提问作者sbrocos
相关产品推荐
相关产品推荐

