Functional tests with Carrierwave

Carrierwave is a really nice gem to use when you want to upload and save a file within a ruby object. But how do you test it, if you don’t use anything more that test/unit or minitest?

Most of the articles describing testing Carrierwave rely on rspec or capybara, but I don’t like adding test gems unless I have to. I prefer to use the test objects provided within the ruby standard library. So test/unit and minitest.

Fortunately, it is fairly easy to manage without anything complicated. All you have to realise is that when a form is submitted to a controller, the uploaded file is presented within params via a ActionDispatch::Http::UploadedFile object.

So for example, I have a model SupportingDocument, which has an attribute ‘document’ that holds the CarrierWave::Uploader associated with uploaded files.

class SupportingDocument < ActiveRecord::Base
  mount_uploader :document, SupportingDocumentUploader
end

To functionally test the supporting_documents controller actions I added a couple of methods to my test SupportingDocumentsControllerTest, that create an UploadedFile object:

  def file
    @file ||= File.open(File.expand_path( '../../file/test.txt', __FILE__))
  end

  def uploaded_file_object(klass, attribute, file, content_type = 'text/plain')
   
    filename = File.basename(file.path)
    klass_label = klass.to_s.underscore
   
    ActionDispatch::Http::UploadedFile.new(
      tempfile: file,
      filename: filename,
      head: %Q{Content-Disposition: form-data; name="#{klass_label}[#{attribute}]"; filename="#{filename}"},
      content_type: content_type
    )
  end

I was then able to use this object within a test:

  def test_create
    name = 'new_supporting_document'
    assert_difference 'SupportingDocument.count' do
        post(
          :create,
          supporting_document: {
            name: name,
            description: 'New supporting document',
            document: uploaded_file_object(SupportingDocument, :document, file)
          },
          notification_id: notification.id
        )
    end
    assert_response :redirect

    supporting_document = SupportingDocument.last
    assert_equal name, supporting_document.name
    assert_equal(File.basename(file.path), supporting_document.document_identifier)
  end
This entry was posted in Ruby. Bookmark the permalink.