When testing Paperclip uploads in my application, I’m interested in treating Paperclip as a black box and trusting it for doing its magic. So what I really need to test is that valid files are processed and invalid ones are not. (see How to allow users to crop images in Rails 4 for model and controller code)

Tests for the model:

require 'test_helper'

class UploadTest < ActiveSupport::TestCase

  def assert_processed(filename, style)
    path = @upload.cargo.path(style)
    assert_match Regexp.new(Regexp.escape(filename) + '$'), path
    assert File.exist?(path), "#{style} not processed"
  end

  def assert_not_processed(filename, style)
    path = @upload.cargo.path(style)
    assert_match Regexp.new(Regexp.escape(filename) + '$'), path
    assert_not File.exist?(@upload.cargo.path(style)), "#{style} unduly processed"
  end

  setup do
    @upload = uploads(:one)
  end

  teardown do
    @upload.cargo.clear
  end

  test 'any image file is attached and thumbnailed' do
    assert_nil @upload.cargo.path(:original)
    assert_nil @upload.cargo.path(:thumb)
    assert_nil @upload.cargo.path(:pinky)

    attachment = File.new("#{Rails.root}/test/fixtures/files/portrait.jpg")
    result = @upload.update_attributes!(:cargo => attachment)

    assert_processed 'portrait.jpg', :original
    assert_processed 'portrait.jpg', :thumb
    assert_processed 'portrait.jpg', :pinky
  end

  test 'any non-image file is attached but not thumbnailed' do
    assert_nil @upload.cargo.path(:original)

    attachment = File.new("#{Rails.root}/test/fixtures/files/document.rtf")
    @upload.update_attributes!(:cargo => attachment)

    assert_processed     'document.rtf', :original
    assert_not_processed 'document.rtf', :thumb
    assert_not_processed 'document.rtf', :pinky
  end

  test 'any attached file is 0 to 5 megabytes' do
    assert_nil @upload.cargo.path(:original)

    # (system console)$ touch /test/fixtures/files/empty
    attachment = File.new("#{Rails.root}/test/fixtures/files/empty")
    @upload.update_attributes!(:cargo => attachment)
    assert_processed 'empty', :original

    # (rails console)> File.open('5-megabytes', 'w') {|f| f.write('$' * 5.megabytes) }
    attachment = File.new("#{Rails.root}/test/fixtures/files/5-megabytes")
    @upload.update_attributes!(:cargo => attachment)
    assert_processed '5-megabytes', :original

    # (rails console)> File.open('5-megabytes-plus-1', 'w') {|f| f.write('$' * (5.megabytes + 1)) }
    attachment = File.new("#{Rails.root}/test/fixtures/files/5-megabytes-plus-1")
    @upload.update_attributes(:cargo => attachment)  # we don't raise a validaton exception here, so no "!"
    assert_not_processed '5-megabytes-plus-1', :original
  end

end

Tests for the controller:

require 'test_helper'

class UploadsControllerTest < ActionController::TestCase
  setup do
    @upload = uploads(:one)
  end

  test "should get index" do
    get :index
    assert_response :success
    assert_not_nil assigns(:uploads)
  end

  test "should get new" do
    get :new
    assert_response :success
  end

  test "should create upload with an image" do
    assert_difference('Upload.count') do
      uploaded = fixture_file_upload('files/portrait.jpg', 'image/jpeg')
      post :create, upload: { name: @upload.name, notes: @upload.notes, owner_id: @upload.owner_id, cargo: uploaded }
    end

    assert_response :success
  end

  test "should create upload with a non-image" do
    assert_difference('Upload.count') do
      uploaded = fixture_file_upload('files/document.rtf', 'application/rtf')
      post :create, upload: { name: @upload.name, notes: @upload.notes, owner_id: @upload.owner_id, cargo: uploaded }
    end

    assert_redirected_to upload_path(assigns(:upload))
  end

  test "should show upload" do
    get :show, id: @upload
    assert_response :success
  end

  test "should get edit" do
    get :edit, id: @upload
    assert_response :success
  end

  test "should update upload" do
    uploaded = fixture_file_upload('files/portrait.jpg', 'image/jpeg')
    patch :update, id: @upload, upload: { name: 'test', notes: 'test', owner_id: @upload.owner_id, cargo: uploaded }
    assert_redirected_to upload_path(assigns(:upload))
  end

  test "should destroy upload" do
    assert_difference('Upload.count', -1) do
      delete :destroy, id: @upload
    end

    assert_redirected_to uploads_path
  end
end