giant robots smashing into other giant robots

We are thoughtbot, a web design and development agency in Boston, MA.

Comments (View)

muck focking

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:


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 CRUD controller.


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.


  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 MIME type. After the POST I assert the file exists.

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


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:


    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.