More articles about Ruby on Rails

File Upload Form Testing Fixtures

By Christopher Haupt

Published February 5, 2008  |   1 comment

Recently, I needed to write my first set of functional tests for a form that is used to upload image assets into our Content Management System. I wanted to find something as easy as fixtures for testing this part of our program.

Whether you are using Rick Olson’s excellent attachment_fu (see Mike Clark’s nice tutorial), Sebastian Kanthak and Jonas Nicklas’ upload_column, or your own code that works with file uploads, you should test this workflow just like any other code path. At first, I thought this was going to be a painful task and require messing around with some custom File I/O or other marshaling trickery. Most of the documentation for 3rd party file upload implementations tended to have little or no information on testing.

Then, while reading through the code a bit more, I stumbled upon fixture_file_upload. This convenience function is tucked away in ActionController’s TestProcess module and is shorthand for instantiating the underlying ActionController::TestUploadedFile class. TestUploadedFile itself is a mock object that simulates the target file that my user would upload in a form or other interface via a MIME multipart/form-data POST.

To use this handy method, I simply put test files in a convenient directory within my fixtures directory, say “files”. Then in a test for upload_column, I write:

def test_should_create_asset
    old_count = Asset.count
    post :create, :asset => { :title => "test", :file => fixture_file_upload('/files/testpicture1.jpg', 'image/jpeg') }
    assert_equal old_count+1, Asset.count
    assert_redirected_to asset_path(assigns(:asset))
 end

Here, the :file attribute for my asset model is expecting an uploaded file from my form, so I feed it one from my fixtures/files directory.

If I use attachment_fu, I may write a create test:

  def test_should_create_asset
    old_count = Asset.count
    post :create, :asset => { :name => 'railslogo', :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') },
                   :html => {:multipart => true }
    assert_equal old_count+1, Asset.count

  end

or an update test:

  def test_should_update_asset
    put :update, {:id => assets(:one).id, :asset => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') }}
    assert_redirected_to asset_path(assigns(:asset))
  end

The TestUploadedFile class is not limited to image data. It can channel any type I may wish into the request. Its default content type assumes text/plain.

Now I can proceed to write a suite of tests for my file upload use cases and let Action Controller and the fixture_file_upload helper do the heavy lifting.

Other Resources


Add your comment on this article






Reader comments on this article

From: Ziemek       Date: 04/29/08 08:08 AM

Subject: Nice Article

short sweet and to the point. Well done!