tester un téléchargement de fichier à l'aide de rspec - rails

142

Je veux tester un téléchargement de fichier dans des rails, mais je ne sais pas comment procéder.

Voici le code du contrôleur:

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

J'ai essayé cette spécification, mais cela ne fonctionne pas:

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

Comment puis-je simuler le téléchargement du fichier à l'aide de rspec?

user727403
la source

Réponses:

291

Vous pouvez utiliser fixture_file_upload méthode pour le téléchargement de fichiers de test: Mettez votre fichier de test dans « {Rails.root} / spec / accessoires / fichiers » répertoire

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

Au cas où vous attendiez le fichier sous la forme de paramètres ['upload'] ['datafile']

it "can upload a license" do
  file = Hash.new
  file['datafile'] = @file
  post :uploadLicense, :upload => file
  response.should be_success
end
ebsbk
la source
8
Cela devrait être marqué comme la réponse, car elle est correcte. Merci mec!
Emil Ahlbäck
30
Voir bit.ly/OSrL7R (question de débordement de pile 3966263) si vous obtenez des erreurs de fichier n'existe pas. Un formulaire différent est nécessaire dans Rails 3.2: @file = Rack :: Test :: UploadedFile.new (Rails.root.join ('spec / fixtures / files / test.csv'), 'text / csv')
Mike Blyth
3
fixture_file_upload fonctionne également si vous spécifiez le chemin complet du fichier: "Rails.root.join ('spec / fixtures / files / test.csv"
jmanrubia
1
fixture_file_upload est traité comme une chaîne de paramètres, quelqu'un sait pourquoi?
Abe Petrillo
3
@AbePetrillo (ou quiconque voit le commentaire et a la même question) J'ai eu le même problème. Dans mon cas, le premier argument pourpost était une méthode d'assistance de chemin, dont le seul argument voulu que je n'ai pas mis entre parenthèses, de sorte que les jetons suivants ont été interprétés comme des arguments supplémentaires pour l'aide, plutôt que comme des arguments pour le message lui-même. Par exemple, j'ai eu post order_documents_path @order, document: fileau lieu de post order_documents_path(@order), document: file.
soupdog
54

Je ne sais pas si vous pouvez tester les téléchargements de fichiers en utilisant uniquement RSpec. Avez-vous essayé Capybara ?

Il est facile de tester les téléchargements de fichiers à l'aide de la attach_fileméthode capybara à partir d'une spécification de demande.

Par exemple (ce code est une démo uniquement):

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
Ken
la source
6
Bien sûr, cela fonctionne dans une spécification d'intégration. La question d'OP concerne une spécification d'unité de contrôleur, étant donné qu'il n'affiche que le code de contrôleur. Je dis juste si quelqu'un est confus. Faites cela dans une spécification de fonctionnalité, faites la réponse d'ebsbk dans une spécification d'unité.
Starkers
2
Le chemin du fichier doit être entre guillemets
sixty4bit
32

si vous incluez Rack :: Test *, incluez simplement les méthodes de test

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

alors vous pouvez utiliser la méthode UploadedFile:

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

* REMARQUE: Mon exemple est basé sur Sinatra, qui étend Rack, mais devrait fonctionner avec Rails, qui utilise également Rack, TTBOMK

zedd45
la source
3
FYI: Vous ne devez pas nécessairement include Rack::Test::Methodsutiliser Rack :: Test :: UploadedFile. require 'rack/testest assez.
xentek
3
Je n'ai même pas à le faire require 'rack/test'. si vous utilisez, Rack::Test::UploadedFilec'est assez bon pour l'utiliser. À condition que la configuration de votre application de rails soit correcte. PS: Je suis sur Rails 4etruby 2.1
Vishnu Narang
Le commentaire de Vishnu est le plus précis, car il exige explicitement la méthode. L'inclusion rack/testinclura tout du test, qui comprend test/methods, mais comprend également tout ce qui est en test, donc probablement plus que ce dont vous avez besoin.
zedd45
18

Je n'ai pas fait cela en utilisant RSpec, mais j'ai un test Test :: Unit qui fait quelque chose de similaire pour télécharger une photo. J'ai configuré le fichier téléchargé en tant qu'instance d'ActionDispatch :: Http :: UploadedFile, comme suit:

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

Quelque chose de similaire pourrait également fonctionner pour vous.

Dave Isaacs
la source
6

C'est comme ça que je l'ai fait avec Rails 6, RSpecetRack::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

N'incluez PASActionDispatch::TestProcess ni aucun autre code, sauf si vous êtes sûr de ce que vous incluez .

cette conception
la source
4

J'ai dû ajouter ces deux inclus pour le faire fonctionner:

describe "my test set" do
  include Rack::Test::Methods
  include ActionDispatch::TestProcess
nfriend21
la source
1
Ne jamais inclure Explication ActionDispatch :: TestProcess: github.com/honeybadger-io/honeybadger-ruby/blob/…
gotar