如何在 Active Storage 测试中存根文件大小? (测试::单位)
How to stub file size on Active Storage test? (Test::Unit)
我在 personal project 中使用 Active Storage。我想检查是否正在验证文件的最大大小。我不想使用真实文件,但我不知道如何存根对象。
测试代码如下:
test "should not upload file bigger than max size allowed" do
refute @page.file.attached?
patch "/#{@page.url}", params: {
page: {
url: "/#{@page.url}",
file: my_stub_file_with_big_size
}
}
assert_response :not_acceptable
@page.reload
refute @page.file.attached?
end
这是对模型的验证:
def file_size
if file.attached? && file.byte_size > MAX_FILE_SIZE
file.purge
errors.add(:file, "File is too big. Max size is 20mb.")
end
end
我更喜欢在单独的 class 中处理给定模型的任何自定义验证,因此我的方法可能不适合您。有关详细信息,请参阅 Rails 文档 here。
在我的自定义验证 class' 测试中,我使用 Rspec 的 receive_message_chain
来存根对 ActiveStorage 图像的任何调用。对于所讨论的模型,我有一个定义了 with_image
特征的工厂(感谢 this related answer),然后我对模型的 image
进行了必要的调用。不幸的是,这需要在您的测试套件中至少有一个图像夹具,但它可以是您想要的任何尺寸。完整示例如下:
user.rb(模型)- 注意使用自定义 target
选项
class User < ApplicationRecord
has_one_attached :image
validates_with ImageValidator, target: :image
end
user.rb(工厂)
FactoryBot.define do
factory :user do
trait :with_image do
after(:build) do |user|
user.image.attach(io: File.open(Rails.root.join('spec', 'fixtures', 'user-image.png')), filename: 'user-image.png', content_type: 'image/png')
end
end
end
end
image_validator.rb(验证 class)- 然后使用自定义 target
选项来确定此 class 应该用于验证给定模型上的哪个属性。
class ImageValidator < ActiveModel::Validator
def validate(record)
if options[:target].present? && record.send(target).attached?
if record.send(target).blob.byte_size > 1000000
record.send(target).purge
record.errors.add(:image, "Image too large")
elsif !record.send(target).blob.content_type.starts_with?('image/')
record.send(target).purge
record.errors.add(:image, "Incorrect image format")
end
end
end
private
def target
options[:target].to_s
end
end
image_validator_spec.rb(测试)
require "rails_helper"
describe ImageValidator do
subject { build(:user, :with_image) }
context "when an Image is too large" do
before do
allow(subject.image).
to receive_message_chain(:blob, :byte_size).and_return(1000001)
end
it "should be invalid" do
expect(subject).to be_invalid
end
end
end
我阅读了您项目中的代码,发现您提出了一个有趣的解决方案,但这里还有另一个符合您要求的解决方案。
第 1 步 - 添加摩卡咖啡
Mocha 是 事实上 MiniTest 爱好者存根库,所以像这样将它添加到您的 Gemfile 中。
group :test do
gem 'mocha'
end
然后 运行 bundle install
并在你的 测试助手 中要求 mocha,如下所示:
# test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'
# add this line
require 'mocha/minitest'
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
end
第 2 步 - 创建虚拟测试文件
在 test/fixtures/files/
中放置一个名为 'test.png' 的小文件。请注意,我的文件大小约为 20KB,非常小。
第 3 步 - 添加单元测试
将以下内容添加到 test/models/page_test.rb
:
test 'file has max size' do
# get the path of the file
fixture_path = File.join(Rails.root, 'test', 'fixtures', 'files', 'test.png')
# open the file
fixture_file = File.open(fixture_path)
# stub the file size to 21 MB
fixture_file.stubs(:size).returns(21.megabytes)
# attach the file to your @page instance
@page.file.attach(io: fixture_file, filename: 'test.png')
# the record should now be invalid
refute @page.valid?
# it should not have an attachment
refute @page.file.attached?
# assert the error message matches a regex
assert_match /is too big/, @page.errors[:file].to_s
end
第 4 步 - 在最大文件大小边界内进行测试
让我们通过将以下内容添加到 test/models/page_test.rb
来确保 20MB 的文件 可以 被接受:
test 'file with valid size' do
# get the path of the file
fixture_path = File.join(Rails.root, 'test', 'fixtures', 'files', 'test.png')
# open the file
fixture_file = File.open(fixture_path)
# stub the file size to 20 MB
fixture_file.stubs(:size).returns(20.megabytes)
# attach the file to your @page instance
@page.file.attach(io: fixture_file, filename: 'test.png')
# the record should now be valid
assert @page.valid?
# it should have an attachment
assert @page.file.attached?
# probably unnecessary, but let's test that there are no errors on @page
assert_empty @page.errors[:file]
end
第 5 步 - 为快乐路径添加控制器测试
让我们为快乐路径添加一个控制器测试:
test 'should update page' do
# fixture_file_upload knows where the fixtures folder is
# and makes sure we have a correctly signed file
fixture_file = fixture_file_upload('files/test.png', 'image/png')
# we need to stub the byte_size of any instance of ActiveStorage::Blob
# as that is what our validations are going to be run against
ActiveStorage::Blob.any_instance.stubs(:byte_size).returns(20.megabytes)
# make sure our ActiveStorage records are created
assert_difference ['ActiveStorage::Blob.count', 'ActiveStorage::Attachment.count'] do
# add our fixture file into the params
patch page_url, params: { page: { file: fixture_file } }
end
# make sure we are redirected to the right place
assert_redirected_to page_url
end
第 6 步 - 为悲伤路径添加控制器测试
测试上传失败时间:
test 'should render edit template when update fails' do
# like before, we get correctly formatted test file by calling
# fixture_file_upload method and passing in the test file
fixture_file = fixture_file_upload('files/test.png', 'image/png')
# stub the byte_size to be 21MB
ActiveStorage::Blob.any_instance.stubs(:byte_size).returns(21.megabytes)
# make sure zero ActiveStorage records are created
assert_no_difference ['ActiveStorage::Blob.count', 'ActiveStorage::Attachment.count'] do
# send the request
patch page_url, params: { page: { file: fixture_file } }
end
# check the response body for an error message
assert_match /is too big/, response.body.to_s
end
就是这样。希望对你有帮助。
我在 personal project 中使用 Active Storage。我想检查是否正在验证文件的最大大小。我不想使用真实文件,但我不知道如何存根对象。
测试代码如下:
test "should not upload file bigger than max size allowed" do
refute @page.file.attached?
patch "/#{@page.url}", params: {
page: {
url: "/#{@page.url}",
file: my_stub_file_with_big_size
}
}
assert_response :not_acceptable
@page.reload
refute @page.file.attached?
end
这是对模型的验证:
def file_size
if file.attached? && file.byte_size > MAX_FILE_SIZE
file.purge
errors.add(:file, "File is too big. Max size is 20mb.")
end
end
我更喜欢在单独的 class 中处理给定模型的任何自定义验证,因此我的方法可能不适合您。有关详细信息,请参阅 Rails 文档 here。
在我的自定义验证 class' 测试中,我使用 Rspec 的 receive_message_chain
来存根对 ActiveStorage 图像的任何调用。对于所讨论的模型,我有一个定义了 with_image
特征的工厂(感谢 this related answer),然后我对模型的 image
进行了必要的调用。不幸的是,这需要在您的测试套件中至少有一个图像夹具,但它可以是您想要的任何尺寸。完整示例如下:
user.rb(模型)- 注意使用自定义 target
选项
class User < ApplicationRecord
has_one_attached :image
validates_with ImageValidator, target: :image
end
user.rb(工厂)
FactoryBot.define do
factory :user do
trait :with_image do
after(:build) do |user|
user.image.attach(io: File.open(Rails.root.join('spec', 'fixtures', 'user-image.png')), filename: 'user-image.png', content_type: 'image/png')
end
end
end
end
image_validator.rb(验证 class)- 然后使用自定义 target
选项来确定此 class 应该用于验证给定模型上的哪个属性。
class ImageValidator < ActiveModel::Validator
def validate(record)
if options[:target].present? && record.send(target).attached?
if record.send(target).blob.byte_size > 1000000
record.send(target).purge
record.errors.add(:image, "Image too large")
elsif !record.send(target).blob.content_type.starts_with?('image/')
record.send(target).purge
record.errors.add(:image, "Incorrect image format")
end
end
end
private
def target
options[:target].to_s
end
end
image_validator_spec.rb(测试)
require "rails_helper"
describe ImageValidator do
subject { build(:user, :with_image) }
context "when an Image is too large" do
before do
allow(subject.image).
to receive_message_chain(:blob, :byte_size).and_return(1000001)
end
it "should be invalid" do
expect(subject).to be_invalid
end
end
end
我阅读了您项目中的代码,发现您提出了一个有趣的解决方案,但这里还有另一个符合您要求的解决方案。
第 1 步 - 添加摩卡咖啡
Mocha 是 事实上 MiniTest 爱好者存根库,所以像这样将它添加到您的 Gemfile 中。
group :test do
gem 'mocha'
end
然后 运行 bundle install
并在你的 测试助手 中要求 mocha,如下所示:
# test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'
# add this line
require 'mocha/minitest'
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
end
第 2 步 - 创建虚拟测试文件
在 test/fixtures/files/
中放置一个名为 'test.png' 的小文件。请注意,我的文件大小约为 20KB,非常小。
第 3 步 - 添加单元测试
将以下内容添加到 test/models/page_test.rb
:
test 'file has max size' do
# get the path of the file
fixture_path = File.join(Rails.root, 'test', 'fixtures', 'files', 'test.png')
# open the file
fixture_file = File.open(fixture_path)
# stub the file size to 21 MB
fixture_file.stubs(:size).returns(21.megabytes)
# attach the file to your @page instance
@page.file.attach(io: fixture_file, filename: 'test.png')
# the record should now be invalid
refute @page.valid?
# it should not have an attachment
refute @page.file.attached?
# assert the error message matches a regex
assert_match /is too big/, @page.errors[:file].to_s
end
第 4 步 - 在最大文件大小边界内进行测试
让我们通过将以下内容添加到 test/models/page_test.rb
来确保 20MB 的文件 可以 被接受:
test 'file with valid size' do
# get the path of the file
fixture_path = File.join(Rails.root, 'test', 'fixtures', 'files', 'test.png')
# open the file
fixture_file = File.open(fixture_path)
# stub the file size to 20 MB
fixture_file.stubs(:size).returns(20.megabytes)
# attach the file to your @page instance
@page.file.attach(io: fixture_file, filename: 'test.png')
# the record should now be valid
assert @page.valid?
# it should have an attachment
assert @page.file.attached?
# probably unnecessary, but let's test that there are no errors on @page
assert_empty @page.errors[:file]
end
第 5 步 - 为快乐路径添加控制器测试
让我们为快乐路径添加一个控制器测试:
test 'should update page' do
# fixture_file_upload knows where the fixtures folder is
# and makes sure we have a correctly signed file
fixture_file = fixture_file_upload('files/test.png', 'image/png')
# we need to stub the byte_size of any instance of ActiveStorage::Blob
# as that is what our validations are going to be run against
ActiveStorage::Blob.any_instance.stubs(:byte_size).returns(20.megabytes)
# make sure our ActiveStorage records are created
assert_difference ['ActiveStorage::Blob.count', 'ActiveStorage::Attachment.count'] do
# add our fixture file into the params
patch page_url, params: { page: { file: fixture_file } }
end
# make sure we are redirected to the right place
assert_redirected_to page_url
end
第 6 步 - 为悲伤路径添加控制器测试
测试上传失败时间:
test 'should render edit template when update fails' do
# like before, we get correctly formatted test file by calling
# fixture_file_upload method and passing in the test file
fixture_file = fixture_file_upload('files/test.png', 'image/png')
# stub the byte_size to be 21MB
ActiveStorage::Blob.any_instance.stubs(:byte_size).returns(21.megabytes)
# make sure zero ActiveStorage records are created
assert_no_difference ['ActiveStorage::Blob.count', 'ActiveStorage::Attachment.count'] do
# send the request
patch page_url, params: { page: { file: fixture_file } }
end
# check the response body for an error message
assert_match /is too big/, response.body.to_s
end
就是这样。希望对你有帮助。