---
title: muck focking
teaser:
tags: web,rails,testing
author: Jared Carroll
published_on: 2007-07-06
---

Most of the time in my tests I mock out all external resources, e.g. file
systems, network I/O, databases, etc.  I recently discovered the
`#fixture_file_upload` method that's available in Rails tests.  File upload was
one area I always mocked out because I didn't even know how to do a file upload
in a functional test.  With this helper method you can do regular state-based
testing with file uploads.

Say you got a `User` who's got an image along side all the normal `User`
attributes.

Schema:

    users (id, email, password)

We'll store the image on the file system:

```ruby
class User < ActiveRecord::Base
  def image=(image)
    file_name = File.join IMAGES_PATH, image.original_filename
    File.open(file_name, 'wb') do |file|
      file.puts image.read
    end
  end
end
```

Our `UsersController` looks the same as any other simple <abbr title="Create
Read Update Delete">CRUD</abbr> controller.

```ruby
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new params[:user]

    if @user.save
      redirect_to user_path(@user)
    else
      render :action => :new
    end
  end
end
```

Now let's take a look at our functional test.

```ruby
def test_should_create_a_new_user_record_on_POST_to_create
  post :create, :user => {
    :email => 'pepper@boloco.com',
    :password => 'burritos',
    :image => fixture_file_upload('images/boloco.gif', 'image/gif') }

  assert File.exists?(File.join(IMAGES_PATH, 'boloco.gif'))
  assert_response :redirect
  assert_redirected_to user_path(assigns(:user))

  assert_recognizes({ :controller => 'users',
                      :action => 'create' },
                    :path => 'users', :method => :post)
end
```

The helper method `#fixture_file_upload` will look for the image file relative
to 'test/fixtures'. I decided to create an 'images' subdirectory there just to
keep it straightforward (as long as I don't have an `Image` model).  The method
takes a filename and its <abbr title="Multi-Purpose Internet Mail
Extension">MIME</abbr> type.  After the `POST` I assert the file exists.

The `IMAGES_PATH` constant is environment specific and defined in
'config/environments/test.rb' as:

```ruby
IMAGES_PATH = File.join RAILS_ROOT, 'tmp', 'images'
```

You might want to throw the following line in your functional test's `#setup`
method to clean up your `IMAGES_PATH` directory:

```ruby
FileUtils.rm_rf Dir["#{IMAGES_PATH}/*"]
```

I don't know if I'd ever write tests like this but mocking has been burning me
lately a bunch so it's good to know I can do state-based file upload testing.
