Skip to Content Collective Idea Home

People Apple Desk by Lee Campbell is licensed under CC0

Testing an Uploaded File in Rspec

Uploading a file without actually uploading it

by Victoria Gonda

I recently wrote a unit test for a bit of code that saves an uploaded file from a controller to the database before pushing it off to a job. I had an example file in spec/fixtures that I wanted to use. Throwing code at the wall, I came up with:

# Does not work!
file = File.new(Rails.root.join("spec/fixtures/filename.xlsx"))
save_uploaded_file_to_db(file)

Then, #save_uploaded_file_to_db gets the parts of the file that we care about, and saves it to the database.

def save_uploaded_file_to_db(file)
  Upload.create(
    filename: File.basename(file.original_filename),
    content_type: file.content_type,
    data: file.read,
  )
end

Looks pretty straightforward, but I got a NoMethodError when calling original_filename. Turns out, this method is unique to UploadedFile. That brought me to the question: “How can I have an uploaded file without uploading something?” I have the answer for you.

Why not instantiate the uploaded file the way we did the file?

file = Rack::Test::UploadedFile.new(Rails.root.join("spec/fixtures/filename.xlsx"))
save_uploaded_file_to_db(file)

Well, that was easy, but it’s not very pretty. Thankfully, there’s a helper method we can use to clean it up. If you have ActionDispatch::TestProcess::FixtureFile included, you can use fixture_file_upload to create an upload file from a file in your test fixtures.

include ActionDispatch::TestProcess::FixtureFile
file = fixture_file_upload("filename.xlsx")
save_uploaded_file_to_db(file)

Easy enough. Then, you can use file the way you were treating your uploaded file. Happy testing!

Comments

Melissa
::

Yay! This helped so much!


Paweł Gościcki
::

Don’t include ActionDispatch::TestProcess. It has some nasty consequences.

Proper solution is to use Rack::Test::UploadedFile directly in the factory (what fixture_file_upload essentially does anyway):

file { Rack::Test::UploadedFile.new('spec/factories/test.png', 'image/png') }