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.
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:
@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:
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