ruby-on-rails - 如何使用 minitest 在 Ruby on Rails 6 中测试文件上传?
问题描述
我有这样的控制器方法:
# POST /v1/scans
def create
p params
uploaded_file = params["pm_file"]
filename = uploaded_file.original_filename
content = uploaded_file.read
parser = ParserStrategy.parser_for filename
file_scan = parser.parse_content content, filename, @api_token.organisation
data = {'scan.id': file_scan.id.to_s}
render json: data, status: :created
rescue => e
Rails.logger.error e.message
Rails.logger.error e.backtrace.join("\n")
end
文件上传工作正常。如果我像这样用 CURL 测试它:
curl -H "Authorization: Bearer QGoEUTK5htI6IT1zyLgKWPqBxv1EXrf7ApSFuuSi" -X POST http://localhost:3000/v1/scans -F pm_file=@composer.json
我得到了预期的结果,参数输出如下所示:
Parameters: {"pm_file"=>#<ActionDispatch::Http::UploadedFile:0x00007f914bae9708 @tempfile=#<Tempfile:/var/folders/ng/h_lxfcf13m71_kgr70_f79hr0000gn/T/RackMultipart20200521-75565-r5a4k1.json>, @original_filename="composer.json", @content_type="application/octet-stream", @headers="Content-Disposition: form-data; name=\"pm_file\"; filename=\"composer.json\"\r\nContent-Type: application/octet-stream\r\n">}
<ActionController::Parameters {"pm_file"=>#<ActionDispatch::Http::UploadedFile:0x00007f914bae9708 @tempfile=#<Tempfile:/var/folders/ng/h_lxfcf13m71_kgr70_f79hr0000gn/T/RackMultipart20200521-75565-r5a4k1.json>, @original_filename="composer.json", @content_type="application/octet-stream", @headers="Content-Disposition: form-data; name=\"pm_file\"; filename=\"composer.json\"\r\nContent-Type: application/octet-stream\r\n">, "controller"=>"v1/scans", "action"=>"create"} permitted: false>
我可以清楚地看到这pm_file
是一个 UploadedFile 类型的对象。现在我想为它写一个自动化测试。用 minitest 这样做:
test "should return 201 because valid request" do
file_path = "#{Rails.root}/test/fixtures/files/composer/composer.json"
composer_file = Rack::Test::UploadedFile.new(file_path, 'application/json', false)
post v1_scans_url, params: { pm_file: composer_file }, headers: { "Authorization" => "Bearer #{@token}" }, as: :json
assert_response 201
end
不幸的是,这不起作用。然后我启动测试,参数输出如下所示:
Parameters: {"pm_file"=>{"original_filename"=>"composer.json", "tempfile"=>"#<File:0x00007fd2a11dff30>", "content_type"=>"application/json"}, "scan"=>{"pm_file"=>{"original_filename"=>"composer.json", "tempfile"=>"#<File:0x00007fd2a11dff30>", "content_type"=>"application/json"}}}
现在pm_file
,它不再是 UploadedFile 类型的 Object,而是一个 Hash。并且代码失败了:
undefined method `original_filename' for #<ActionController::Parameters:0x00007fd2859c2278>
同样的情况也发生在fixture_file_upload
. 这个测试带来了完全相同的结果:
test "should return 201 because valid request" do
file_path = "#{Rails.root}/test/fixtures/files/composer/composer.json"
composer_file = fixture_file_upload("#{Rails.root}/test/fixtures/files/composer/composer.json",'application/json')
post v1_scans_url, params: { pm_file: composer_file }, headers: { "Authorization" => "Bearer #{@token}" }, as: :json
assert_response 201
end
我做错了什么?如何正确测试 Rails 6 中的文件上传?
解决方案
问题是我试图通过 JSON 发送文件。删除as: :json
帖子末尾的代码段后,它按预期工作。所以这里的这个测试就像使用 Minitest 上传文件的预期一样工作:
test "should return 201 because valid request" do
file_path = "#{Rails.root}/test/fixtures/files/composer/composer.json"
composer_file = fixture_file_upload("#{Rails.root}/test/fixtures/files/composer/composer.json",'application/json')
post v1_scans_url, params: { pm_file: composer_file }, headers: { "Authorization" => "Bearer #{@token}" }
assert_response 201
end
推荐阅读
- python - 使用 Django 进行 APIS 之间的通信?
- xml - XSLT + XML - 过滤结果
- node.js - 尝试使用密码安全地解密私钥
- javascript - Reactjs firebase firestore 通过 currentUser.id 从集合过滤器中获取数据
- javascript - 制作固定侧边栏在到达页脚时开始滚动
- php - SQLSTATE[IM001]:驱动程序不支持此功能:驱动程序不支持该属性
- maven - 无法在 com.marklogic-datahub-jar:4.3.1 收集依赖项
- python - 如何解释这种跨 CPU 内核分布式训练的回溯?
- python - 尝试在运行时在 python REVISITED 中检查 chromedriver.exe 版本
- docker - Docker 在 npm-cli-adduser 中“过于冗长”