如何在 Rails 中正确使用 ActiveStorage 进行模型测试?
Posted
技术标签:
【中文标题】如何在 Rails 中正确使用 ActiveStorage 进行模型测试?【英文标题】:How to properly do model testing with ActiveStorage in rails? 【发布时间】:2018-05-14 23:56:51 【问题描述】:我刚刚切换到在 rails 5.1.4 上使用 ActiveStorage,我是 TDD 新手,正在努力弄清楚如何测试 has_one_attached :avatar
的模型
require 'rails_helper'
RSpec.describe User, :type => :model do
let (:valid_user) FactoryBot.build(:user)
describe "Upload avatar" do
context "with a valid image" do
it "saves the image" do
valid_user.save!
saved_file = valid_user.avatar.attach(io: File.open("/home/ubuntu/workspace/spec/fixtures/files/avatar.jpg"), filename: "face.jpg", content_type: "image/jpg")
expect(saved_file).to be_an_instance_of(ActiveStorage::Attachment::One)
end
end
end
end
但我收到以下错误:
Failures:
1) User Upload avatar with a valid image saves the image
Failure/Error:
saved_file = valid_user.avatar.attach(io: File.open("/home/ubuntu/workspace/spec/fixtures/files/avatar.jpg"), filename: "face.jpg",
content_type: "image/jpg")
NoMethodError:
undefined method `upload' for nil:NilClass
Did you mean? load
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/blob.rb:48:in `upload'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/blob.rb:21:in `block in build_after_upload'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/blob.rb:16:in `tap'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/blob.rb:16:in `build_after_upload'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/blob.rb:26:in `create_after_upload!'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/attached.rb:25:in `create_blob_from'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/attached/one.rb:9:in `attach'
# ./spec/models/user_spec.rb:47:in `block (4 levels) in <top (required)>'
有什么提示吗?
【问题讨论】:
提示:expect(valid_user.image.attached?).to be true
因为您不需要测试 ActiveStorage 的内部结构。
expect(valid_user.image).to be_attached
是一样的,但 RSpec 更惯用一点
【参考方案1】:
我解决了
FactoryBot.define do
factory :culture do
name 'Soy'
after(:build) do |culture|
culture.image.attach(io: File.open(Rails.root.join('spec', 'factories', 'images', 'soy.jpeg')), filename: 'soy.jpeg', content_type: 'image/jpeg')
end
end
end
之后
describe '#image' do
subject create(:culture).image
it is_expected.to be_an_instance_of(ActiveStorage::Attached::One)
end
【讨论】:
这会给你一个可能的误报,因为图像总是 ActiveStorage::Attached::One 的一个实例,即使它是 nil。在控制台中尝试以下操作:User.new.avatar
。请注意,它是 ActiveStorage::Attached::One 的一个实例。【参考方案2】:
问题解决了。在将错误跟踪到 ActiveStorage::Blob::upload 方法后,它说:Uploads the io to the service on the key for this blob.
我意识到我没有为测试环境设置 active_storage.service。简单来说就是加:
config.active_storage.service = :test
到 config/environments/test.rb 文件
【讨论】:
不高兴地尝试了另一个答案 - 这对我有用,谢谢 如果某些型号有回形针和其他 Activestorage,有什么方法可以设置?【参考方案3】:我是这样解决的
# model
class Report < ApplicationRecord
has_one_attached :file
end
# factory
FactoryBot.define do
factory :report, class: Report do
any_extra_field 'its value'
end
end
# spec
require 'rails_helper'
RSpec.describe Report, type: :model do
context "with a valid file" do
before(:each) do
@report = create(:report)
end
it "is attached" do
@report.file.attach(
io: File.open(Rails.root.join('spec', 'fixtures', 'file_name.xlsx')),
filename: 'filename.xlsx',
content_type: 'application/xlsx'
)
expect(@report.file).to be_attached
end
end
end
希望对你有帮助
【讨论】:
这对我来说是更好的测试,您实际检查该项目是否已附加。谢谢。【参考方案4】:在 config/environments/test.rb 中
config.active_storage.service = :test
在你的规范中
it expect(valid_user.avatar).to be_attached
【讨论】:
【参考方案5】:我遇到了类似的 nil 错误(Module::DelegationError: to_model delegated to attachment,但 attachment 是 nil),但它只发生在多个测试使用同一个工厂时。
问题似乎是上一个测试拆解中的清理是在下一次工厂调用附加该文件后删除该文件。关键是将 ActiveJob 队列适配器更新为内联,以便立即删除文件。
将这两个设置添加到 config/environments/test.rb:
# Use inline job processing to make things happen immediately
config.active_job.queue_adapter = :inline
# Store uploaded files on the local file system in a temporary directory.
config.active_storage.service = :test
【讨论】:
【参考方案6】:为什么不:
RSpec.describe User, type: :model do
describe 'relations' do
it is_expected.to have_one(:avatar_attachment)
end
end
【讨论】:
【参考方案7】:在这些帖子的帮助下,我对 Rails 6.1 的主动存储进行了 rspec 测试的更新
# .\spec\models\activestorage_spec.rb
require 'rails_helper'
RSpec.describe User, :type => :model do
before(:each) do
@user = FactoryBot.create(:user)
@user.save!
saved_file = @user.pictures.attach(io: File.open("./storage/test.jpg"), filename: "test.jpg", content_type: "image/jpg")
end
describe "Upload picture" do
context "with a valid picture" do
it "saves the picture" do
expect(@user.pictures).to be_attached
end
end
end
end
现在您只能添加更多测试
【讨论】:
以上是关于如何在 Rails 中正确使用 ActiveStorage 进行模型测试?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ruby 或 rails 中正确使用 use Noty
如何在 Rails 中正确使用控制器辅助模块,以及如何连接这些辅助模块?