Testing an Uploaded File in Rspec

Uploading a file without actually uploading it

People Apple Desk by Lee Campbell is licensed under CC0

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!

Photo of Victoria Gonda

Victoria is a software developer working on mobile and full stack web applications. She enjoys exchanging knowledge through conference talks and writing.

Comments

Add a Comment

Hmm...that didn't work.

Something went wrong while adding your comment. If you don't mind, please try submitting it again.

Comment Added!

Your comment has been added to this post. Please refresh this page to view it.

Optional. If added, we will display a link to the website in your comment.
Optional. Never shared or displayed in your comment.
  1. Melissa
    February 13, 2017 at 17:47 PM

    Yay! This helped so much!

  2. July 06, 2017 at 7:06 AM

    Very informative. . .

  3. November 15, 2018 at 13:32 PM

    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') }