【问题标题】:test a file upload using rspec - rails使用 rspec 测试文件上传 - rails
【发布时间】:2011-11-07 19:00:17
【问题描述】:

我想在 Rails 中测试文件上传,但不知道该怎么做。

这是控制器代码:

def uploadLicense
    #Create the license object
    @license = License.create(params[:license]) 


    #Get Session ID
    sessid = session[:session_id]

    puts "\n\nSession_id:\n#{sessid}\n"

    #Generate a random string
    chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
    newpass = ""
    1.upto(5) { |i| newpass << chars[rand(chars.size-1)] }

    #Get the original file name
    upload=params[:upload]
    name =  upload['datafile'].original_filename 

    @license.format = File.extname(name)

    #calculate license ID and location
    @license.location = './public/licenses/' + sessid + newpass + name 

    #Save the license file
    #Fileupload.save(params[:upload], @license.location) 
    File.open(@license.location, "wb") { |f| f.write(upload['datafile'].read) }

     #Set license ID
    @license.license_id = sessid + newpass

    #Save the license
    @license.save

    redirect_to :action => 'show', :id => @license.id 
end

我已经尝试过这个规范,但它不起作用:

it "can upload a license and download a license" do
    file = File.new(Rails.root + 'app/controllers/lic.xml')
    license = HashWithIndifferentAccess.new
    license[:datafile] = file
    info = {:id => 4}
    post :uploadLicense, {:license => info, :upload => license}
end

如何使用 rspec 模拟文件上传?

【问题讨论】:

    标签: ruby-on-rails file-upload tdd rspec-rails


    【解决方案1】:

    您可以使用fixture_file_upload 方法来测试文件上传: 将您的测试文件放入 "{Rails.root}/spec/fixtures/files" 目录

    before :each do
      @file = fixture_file_upload('files/test_lic.xml', 'text/xml')
    end
    
    it "can upload a license" do
      post :uploadLicense, :upload => @file
      response.should be_success
    end
    

    如果您希望文件格式为 params['upload']['datafile']

    it "can upload a license" do
      file = Hash.new
      file['datafile'] = @file
      post :uploadLicense, :upload => file
      response.should be_success
    end
    

    【讨论】:

    • 这应该被标记为答案,因为它是正确的。谢谢大佬!
    • 如果您收到文件不存在错误,请参阅bit.ly/OSrL7R(堆栈溢出问题 3966263)。 Rails 3.2 需要不同的形式:@file = Rack::Test::UploadedFile.new(Rails.root.join('spec/fixtures/files/test.csv'), 'text/csv')
    • 如果您指定文件的完整路径,fixture_file_upload 也可以工作:"Rails.root.join('spec/fixtures/files/test.csv"
    • fixture_file_upload 在参数中被视为字符串,有人知道为什么吗?
    • @AbePetrillo(或任何看到评论并有相同问题的人)我遇到了同样的问题。在我的例子中,post 的第一个参数是路径辅助方法,我没有将其唯一的预期参数括在括号中,因此以下标记被解释为辅助方法的附加参数,而不是帖子本身的参数。例如,我有 post order_documents_path @order, document: file 而不是 post order_documents_path(@order), document: file
    【解决方案2】:

    我不确定您是否可以单独使用 RSpec 测试文件上传。你试过Capybara吗?

    使用请求规范中的 capybara 的 attach_file 方法很容易测试文件上传。

    例如(此代码仅供演示):

    it "can upload a license" do
      visit upload_license_path
      attach_file "uploadLicense", /path/to/file/to/upload
      click_button "Upload License"
    end
    
    it "can download an uploaded license" do
      visit license_path
      click_link "Download Uploaded License"
      page.should have_content("Uploaded License")
    end
    

    【讨论】:

    • 当然这适用于集成规范。 OP 的问题是关于控制器单元规格的,考虑到他只是发布控制器代码。只是说如果有人感到困惑。在功能规范中执行此操作,在单元规范中执行 ebsbk 的回答。
    • 文件路径需要加引号
    【解决方案3】:

    如果包含 Rack::Test*,只需包含测试方法

    describe "my test set" do
      include Rack::Test::Methods
    

    那么你可以使用 UploadedFile 方法:

    post "/upload/", "file" => Rack::Test::UploadedFile.new("path/to/file.ext", "mime/type")
    

    *注意:我的示例基于 Sinatra,它扩展了 Rack,但应该与 Rails 一起使用,Rails 也使用 Rack、TTBOMK

    【讨论】:

    • 仅供参考:您不一定非要include Rack::Test::Methods 才能使用 Rack::Test::UploadedFile。 require 'rack/test 就够了。
    • 我什至不必require 'rack/test'。如果您使用的是Rack::Test::UploadedFile,那就可以使用它了。前提是您的 Rails 应用程序设置很好。 PS:我在Rails 4ruby 2.1
    • Vishnu 的评论是最准确的,因为他明确要求该方法。包括rack/test 将包括来自测试的所有内容,其中包括test/methods,但还包括测试中的所有内容,因此可能超出您的需要。
    【解决方案4】:

    我没有使用 RSpec 完成此操作,但我确实有一个 Test::Unit 测试,它可以为上传照片执行类似的操作。我将上传的文件设置为ActionDispatch::Http::UploadedFile的实例,如下:

    test "should create photo" do
      setup_file_upload
      assert_difference('Photo.count') do
        post :create, :photo => @photo.attributes
      end
      assert_redirected_to photo_path(assigns(:photo))
    end
    
    
    def setup_file_upload
      test_photo = ActionDispatch::Http::UploadedFile.new({
        :filename => 'test_photo_1.jpg',
        :type => 'image/jpeg',
        :tempfile => File.new("#{Rails.root}/test/fixtures/files/test_photo_1.jpg")
      })
      @photo = Photo.new(
        :title => 'Uploaded photo', 
        :description => 'Uploaded photo description', 
        :filename => test_photo, 
        :public => true)
    end
    

    类似的东西也可能对你有用。

    【讨论】:

      【解决方案5】:

      这就是我使用Rails 6RSpecRack::Test::UploadedFile 的方式

      describe 'POST /create' do
        it 'responds with success' do
          post :create, params: {
            license: {
              picture: Rack::Test::UploadedFile.new("#{Rails.root}/spec/fixtures/test-pic.png"),
              name: 'test'
            }
          }
      
          expect(response).to be_successful
        end
      end
      

      DO NOT include ActionDispatch::TestProcess 或任何其他代码,除非您确定您所包含的内容。

      【讨论】:

        【解决方案6】:

        我必须添加这两个包含才能使其正常工作:

        describe "my test set" do
          include Rack::Test::Methods
          include ActionDispatch::TestProcess
        

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-26
        • 1970-01-01
        • 1970-01-01
        • 2012-09-26
        相关资源
        最近更新 更多