протестировать загрузку файла с помощью rspec - rails

144

Я хочу протестировать загрузку файла в рельсы, но не знаю, как это сделать.

Вот код контроллера:

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?

user727403
источник

Ответы:

293

Вы можете использовать fixture_file_upload метод для загрузки тестового файла: Поместите файл тест в «{Rails.root} / спецификация / приборы / файлы» каталог

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
ebsbk
источник
8
Это следует отметить как ответ, потому что он правильный. Спасибо чувак!
Emil Ahlbäck
30
См. Bit.ly/OSrL7R (вопрос о переполнении стека 3966263), если вы получаете ошибку «файл не существует». В Rails 3.2 требуется другая форма: @file = Rack :: Test :: UploadedFile.new (Rails.root.join ('spec / fixtures / files / test.csv'), 'text / csv')
Майк Блит
3
fixture_file_upload также работает, если вы укажете полный путь к файлу: "Rails.root.join ('spec / fixtures / files / test.csv"
jmanrubia
1
fixture_file_upload обрабатывается как строка в params, кто-нибудь знает почему?
Эйб Петрилло
3
@AbePetrillo (или тот, кто видит комментарий и задает тот же вопрос) У меня была такая же проблема. В моем случае первым аргументом postбыл вспомогательный метод пути, единственный предполагаемый аргумент которого я не заключил в круглые скобки, поэтому следующие токены были интерпретированы как дополнительные аргументы для вспомогательного метода, а не как аргументы для самого сообщения. Например, post order_documents_path @order, document: fileвместо post order_documents_path(@order), document: file.
soupdog
55

Я не уверен, что вы можете тестировать загрузку файлов, используя только RSpec. Вы пробовали Capybara ?

Легко протестировать загрузку файлов с помощью attach_fileметода capybara из спецификации запроса.

Например (этот код является только демонстрационным):

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
Кен
источник
7
Конечно, это работает в спецификации интеграции. Вопрос OP касается спецификации блока контроллера, учитывая, что он только публикует код контроллера. Просто говорю, если кто-то запутался. Сделайте это в спецификации функции, ответьте ebsbk в спецификации устройства.
Starkers
2
Путь к файлу должен быть в кавычках
sixty4bit
33

если вы включите 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, который также использует Rack, TTBOMK

zedd45
источник
3
К вашему сведению: вам не обязательно include Rack::Test::Methodsиспользовать Rack :: Test :: UploadedFile. require 'rack/testдостаточно.
xentek
3
Мне даже не нужно require 'rack/test'. если вы используете, Rack::Test::UploadedFileэтого достаточно, чтобы использовать. При условии, что ваша установка приложения rails в порядке. PS: Я иду Rails 4иruby 2.1
Вишну Наранг
Комментарий Вишну является наиболее точным, поскольку он явно требует метода. В том числе rack/testбудет все от теста, которое включает test/methods, но также включает все в тесте, так что, вероятно, больше, чем вам нужно.
zedd45
18

Я не делал этого с помощью 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

Что-то подобное может сработать и для вас.

Дэйв Айзекс
источник
7

Вот как я это сделал Rails 6, RSpecиRack::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

НЕ включайтеActionDispatch::TestProcess любой другой код, если вы не уверены в том, что включаете.

это
источник
4

Мне пришлось добавить оба этих включения, чтобы заставить его работать:

describe "my test set" do
  include Rack::Test::Methods
  include ActionDispatch::TestProcess
nfriend21
источник
1
Никогда не включайте ActionDispatch :: объяснение TestProcess: github.com/honeybadger-io/honeybadger-ruby/blob/…
gotar