probar la carga de un archivo usando rspec - rails

142

Quiero probar la carga de un archivo en rieles, pero no estoy seguro de cómo hacerlo.

Aquí está el código del controlador:

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

He intentado esta especificación, pero no funciona:

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

¿Cómo puedo simular la carga del archivo usando rspec?

usuario727403
fuente

Respuestas:

291

Puede utilizar fixture_file_upload método para la carga de archivos de ensayo: Poner el archivo de prueba en "/ spec / accesorios / archivos {} Rails.root" directorio

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

En caso de que esperara el archivo en forma de params ['upload'] ['datafile']

it "can upload a license" do
  file = Hash.new
  file['datafile'] = @file
  post :uploadLicense, :upload => file
  response.should be_success
end
ebsbk
fuente
8
Esto debe marcarse como la respuesta, porque es correcto. ¡Gracias hombre!
Emil Ahlbäck
30
Vea bit.ly/OSrL7R (pregunta de desbordamiento de pila 3966263) si está recibiendo errores de archivo no existe. Se necesita una forma diferente en Rails 3.2: @file = Rack :: Test :: UploadedFile.new (Rails.root.join ('spec / fixtures / files / test.csv'), 'text / csv')
Mike Blyth
3
fixture_file_upload también funciona si especifica la ruta completa al archivo: "Rails.root.join ('spec / fixtures / files / test.csv"
jmanrubia
1
fixture_file_upload se trata como una cadena en los parámetros, ¿alguien sabe por qué?
Abe Petrillo
3
@AbePetrillo (o quien vea el comentario y tenga la misma pregunta) Tuve el mismo problema. En mi caso, el primer argumento postfue un método de ayuda de ruta, cuyo único argumento intencionado no incluí entre paréntesis, por lo que los siguientes tokens se interpretaron como argumentos adicionales para el asistente, en lugar de argumentos para la publicación en sí. Por ejemplo, tuve en post order_documents_path @order, document: filelugar de post order_documents_path(@order), document: file.
Souvenir
54

No estoy seguro de si puede probar la carga de archivos utilizando solo RSpec. ¿Has probado Carpincho ?

Es fácil probar las cargas de archivos utilizando el attach_filemétodo de capibara a partir de una especificación de solicitud.

Por ejemplo (este código es solo una demostración):

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
Conocido
fuente
66
Por supuesto, esto funciona en una especificación de integración. La pregunta de OP se refiere a una especificación de unidad de controlador, considerando que solo está publicando un código de controlador. Solo digo si alguien está confundido. Haga esto en una especificación de características, haga la respuesta de ebsbk en una especificación de unidad.
Starkers
2
La ruta del archivo debe estar entre comillas
sixty4bit
32

si incluye Rack :: Test *, simplemente incluya los métodos de prueba

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

entonces puedes usar el método UploadedFile:

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

* NOTA: Mi ejemplo se basa en Sinatra, que extiende Rack, pero debería funcionar con Rails, que también usa Rack, TTBOMK

zedd45
fuente
3
FYI: No necesariamente tiene include Rack::Test::Methodsque usar Rack :: Test :: UploadedFile. require 'rack/testes suficiente.
xentek
3
Ni siquiera tengo que hacerlo require 'rack/test'. si está usando Rack::Test::UploadedFileeso es lo suficientemente bueno como para usarlo. Siempre que la configuración de la aplicación rails esté bien. PD: Estoy encendido Rails 4yruby 2.1
Vishnu Narang
El comentario de Vishnu es el más preciso, ya que requiere el método explícitamente. La inclusión rack/testincluirá todo, desde la prueba, que incluye test/methods, pero también incluye todo en la prueba, por lo que probablemente sea más de lo que necesita.
zedd45
18

No he hecho esto usando RSpec, pero tengo una prueba Test :: Unit que hace algo similar para cargar una foto. Configuré el archivo cargado como una instancia de ActionDispatch :: Http :: UploadedFile, de la siguiente manera:

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

Algo similar podría funcionar para usted también.

Dave Isaacs
fuente
6

Así es como lo hice Rails 6, RSpecyRack::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

NO incluyaActionDispatch::TestProcess ni ningún otro código a menos que esté seguro de lo que está incluyendo.

este es mi diseño
fuente
4

Tuve que agregar ambos de estos incluye para que funcione:

describe "my test set" do
  include Rack::Test::Methods
  include ActionDispatch::TestProcess
nfriend21
fuente
1
Nunca incluya ActionDispatch :: Explicación de TestProcess
gotar