перевірити завантаження файлів за допомогою rspec - рейли


142

Я хочу перевірити завантаження файлів у рейках, але не знаю, як це зробити.

Ось код контролера:

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?

Відповіді:


291

Ви можете використовувати 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'] ['filefile']

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

8
Це слід позначити як відповідь, оскільки це правильно. Спасибі людино!
Еміль Альбак

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 трактується як параметр у парамах, хтось знає чому?
Abe Petrillo

3
@AbePetrillo (або той, хто бачить коментар і має те саме запитання) У мене був той самий випуск. У моєму випадку першим аргументом postбув метод допоміжної контури, єдиний призначений аргумент я не вкладав у дужки, тому такі лексеми інтерпретувались як додаткові аргументи для помічника, а не аргументи для самої публікації. Наприклад, я мав post order_documents_path @order, document: fileзамість цього post order_documents_path(@order), document: file.
супина

54

Я не впевнений, чи можна випробувати завантаження файлів, використовуючи лише RSpec. Ви пробували Капібару ?

Тестувати завантаження файлів легко за допомогою 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

6
Звичайно, це працює в специфікації інтеграції. Питання ОП стосується специфікації блоку контролера, враховуючи, що він розміщує лише код контролера. Просто кажу, якщо хтось бентежить. Зробіть це в специфікації функції, виконайте відповідь ebsbk в одиниці специфікації.
Старкерс

2
Шлях до файлу має бути в лапках
шістдесят біт

32

якщо ви включаєте 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


3
FYI: Вам не обов’язково include Rack::Test::Methodsвикористовувати Rack :: Test :: UploadedFile. require 'rack/testдостатньо.
xentek

3
Я навіть не повинен require 'rack/test'. якщо ви використовуєте Rack::Test::UploadedFileце досить добре, щоб ним користуватися. За умови налаштування додатка для рейкових плат. PS: Я ввімкнув Rails 4іruby 2.1
Vishnu Narang

Коментар Вішну є найбільш точним, оскільки він вимагає методу прямо. У тому числі 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

Щось подібне може працювати і для вас.


6

Ось як я це зробив 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

1
Ніколи не включайте ActionDispatch :: Пояснення TestProcess
gotar
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.