Forum: Ruby on Rails testing file uploads

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Sam J. (Guest)
on 2006-01-05 21:21
(Received via mailing list)
Hi all,

I was wondering about the class used when rails receives file uploads.
Sometimes it appears to be a File, and other times it is a StringIO.
Also it has methods such as original_filename that don't appear to
belong to either of these classes. I ask because I'm trying to work out
how to test my fil upload related models and controllers.

Is there some standardised way of creating a file upload mock object?

Many thanks in advance.

CHEERS> SAM
Marcel Molina Jr. (Guest)
on 2006-01-06 02:16
(Received via mailing list)
On Fri, Jan 06, 2006 at 04:20:00AM +0900, Sam J. wrote:
> I was wondering about the class used when rails receives file uploads.
> Sometimes it appears to be a File, and other times it is a StringIO.
> Also it has methods such as original_filename that don't appear to
> belong to either of these classes. I ask because I'm trying to work out
> how to test my fil upload related models and controllers.
>
> Is there some standardised way of creating a file upload mock object?
>
> Many thanks in advance.

Here's some code for testing file uploads. This has some bits that are
specific
to the implementation so you can't just copy and paste this wholesale
and
expect it to work but perhaps it can provide some direction.

In the test_helper.rb:

  module UploadedFile
    attr_accessor :original_filename, :content_type
  end

  def uploaded_file(contents, name, content_type)
    io = StringIO.new(contents)
    io.extend UploadedFile
    io.original_filename = name
    io.content_type = content_type
    io
  end

  def empty_trash!
    FileUtils.rm_rf(Dir["#{Upload.upload_root}/*"])
  end

  def file_uploaded?(file_name)
    File.exists?(uploaded_file_path(file_name))
  end

  def assert_file_uploaded(file_name)
    assert file_uploaded?(file_name)
  end

  def assert_file_not_uploaded(file_name)
    assert !file_uploaded?(file_name)
  end

  def assert_upload_equals(contents, file_name)
    assert_file_uploaded file_name
    assert_equal contents, IO.read(uploaded_file_path(file_name))
  end

  def uploaded_file_path(file_name)
    namespace =
Upload.namespace_directories(@controller.send(:account).id)
    File.join(Upload.upload_root, namespace, file_name)
  end

The functional tests look something like this:

  def teardown
    empty_trash!
  end

  def test_basic_upload
    assert_difference_in_size(Upload) do
      upload = uploaded_file('Rock out!', 'nsync.mp3', 'audio/mpg')
      post :new, :upload => upload
      assert_file_uploaded 'nsync.mp3'
      assert_not_nil assigns(:upload).upload_message
    end
  end

  def test_all_upload_metadata_set
    upload = uploaded_file('La la la', 'jason-in-shower.mp3',
'audio/mpg')
    post :new, :upload => upload
    record = assigns(:upload)
    assert_equal 'La la la'.size, record.byte_size
    assert_equal 'audio/mpg', record.content_type
    assert_equal 'jason-in-shower.mp3', record.name
  end

And finally, though not central to testing the uploading specifically,
here is
assert_difference_in_size (which I pretty much use all the time
everywhere):

  def assert_difference_in_size(object, methods = nil, difference = 1)
    methods ||= :count
    apply = Proc.new {|obj, methods|
      [*methods].inject(object) {|result, method| result.send(method)}
    }
    initial_value = apply.call(object, methods)
    yield
    assert_equal initial_value + difference, apply.call(object, methods)
  end

  def assert_no_difference_in_size(object, methods = nil, &block)
    assert_difference_in_size object, methods, 0, &block
  end

Quack!
marcel
Sam J. (Guest)
on 2006-01-08 01:20
(Received via mailing list)
Hi Marcel,

Thanks - this is very helpful.

I also wonder is this the way that rails itself handles incoming files,
i.e. it takes a StringIO or File object and uses the extend operation to
add meta-data?

CHEERS> SAM
Marcel Molina Jr. (Guest)
on 2006-01-08 01:56
(Received via mailing list)
On Sun, Jan 08, 2006 at 08:18:38AM +0900, Sam J. wrote:
> I also wonder is this the way that rails itself handles incoming files,
> i.e. it takes a StringIO or File object and uses the extend operation to
> add meta-data?

Rails isn't responsible for any of this actually. It is ruby's cgi.rb
that
handles file uploads and creating an IO object with metadata.

marcel
Scott B. (Guest)
on 2006-01-08 02:11
(Received via mailing list)
On Fri, Jan 06, 2006 at 04:20:00AM +0900, Sam J. wrote:
> Many thanks in advance.
>
> CHEERS> SAM

I do some basic file upload testing with this set up:

http://rubyi.st/show/9

YMMV, of course, depending on the complexity you need.

-Scott
This topic is locked and can not be replied to.