Unit testing paperclip uploads with Rspec (Rails)

26,770

Solution 1

This should work with Rails 2.X:

Image.new :photo => File.new(RAILS_ROOT + '/spec/fixtures/images/rails.png')

As of Rails 3, RAILS_ROOT is no longer used, instead you should use Rails.root.

This should work with Rails 3:

Image.new :photo => File.new(Rails.root + 'spec/fixtures/images/rails.png')

Definitely get the RSpec book, it's fantastic.

Solution 2

Rails.root is a pathname object so you can use it like this:

Image.new :photo => Rails.root.join("spec/fixtures/images/rails.png").open

Edit - probably does not work in Rails 3...

  • see answer by @Paul Rosania

Solution 3

In case anyone else finds this via Google, RAILS_ROOT is no longer valid in Rails 3.0. That line should read:

Image.new :photo => File.new(Rails.root + 'spec/fixtures/images/rails.png')

(Note the lack of leading slash!)

Solution 4

I use the multipart_body gem in my integration tests. Its a bit truer to BDD than testing.

http://steve.dynedge.co.uk/2010/09/19/multipart-body-a-gem-for-working-with-multipart-data/

With respect to rspec and paperclip, the has_attached_file :photo directive creates a virtual attribute of sorts i.e. :photo ... when you assign a file or a path to photo, paperclip takes over, stores the file, optionally does processing on it e.g. auto-create thumbnails, import a spreadsheet, etc. You aren't telling rspec to test paperclip. You are invoking code and telling rspec what the results of that code -should- be.

In $GEM_HOME/gems/paperclip-2.3.8/README.rdoc, about 76% of the way through the file under ==Post Processing (specifically lines 147 and 148):

---[ BEGIN QUOTE ]--- NOTE: Because processors operate by turning the original attachment into the styles, no processors will be run if there are no styles defined. ---[ END QUOTE ]---

Reading the code, you'll see support :original ... does your has_attached_file define a style?

I use a generic ":styles => { :original => { :this_key_and => :this_value_do_not_do_anything_unless_a_lib_paperclip_processors__foo_dot_rb__does_something_with_them } }" ... just to get paperclip to move the file from some temp directory into my has_attached_file :path

One would think that would be default or more obvious in the docs.

Share:
26,770

Related videos on Youtube

stephenmurdoch
Author by

stephenmurdoch

Updated on July 09, 2022

Comments

  • stephenmurdoch
    stephenmurdoch almost 2 years

    Total Rspec noob here. Writing my first tests tonight.

    I've got a model called Image. Using paperclip I attach a file called photo. Standard stuff. I've run the paperclip generator and everything works fine in production and test modes.

    Now I have a spec file called image.rb and it looks like this (it was created by ryanb's nifty_scaffold generator):

    require File.dirname(__FILE__) + '/../spec_helper'
    
    describe Image do
    
      it "should be valid" do
        Image.new.should be_valid
      end
    end
    

    This test fails and I realise that it's because of my model validations (i.e. validates_attachment_presence)

    The error that I get is:

    Errors: Photo file name must be set., Photo file size file size must be between 0 and 1048576 bytes., Photo content type is not included in the list
    

    So how do I tell rspec to upload a photo when it runs my test?

    I'm guessing that it's got somethign to do with fixtures.... maybe not though. I've tried playing around with them but not having any luck. For the record, I've created a folder called images inside my fixtures folder and the two files I want to use in my tests are called rails.png and grid.png)

    I've tried doing the following:

    it "should be valid" do
      image = Image.new :photo => fixture_file_upload('images/rails.png', 'image/png').should be_valid 
    
      # I've also tried adding stuff like this
      #image.stub!(:has_attached_file).with(:photo).and_return( true )
      #image.stub!(:save_attached_files).and_return true
      #image.save.should be_true  
    end
    

    But rspec complains about "fixture_file_upload" not being recognised... I am planning to get that Rspec book. And I've trawled around the net for an answer but can't seem to find anything. My test database DOES get populated with some data when I remove the validations from my model so I know that some of it works ok.

    Thanks in advance,

    EDIT:

    images.yml looks like this:

    one:
      name: MyString
      description: MyString
    
    two:
      name: MyString
      description: MyString
    
  • nnyby
    nnyby almost 14 years
    What if the model doesn't have a 'photo' field? Is it supposed to work still? I have this in my spec/factories.rb: comment.pic File.new(RAILS_ROOT + '/spec/fixtures/images/rails.png') And I'm getting the RSpec error: ActiveRecord::RecordInvalid in 'Comment should create a new instance given valid attributes'Validation failed: Pic file name image is required
  • Ruxton
    Ruxton almost 14 years
    I'm guessing whatever you've put in the model for has_attached_file goes in place of the :photo so if you've written has_attached_file :donkey then you'd write Image.new :donkey => File.new etc.
  • Amin Ariana
    Amin Ariana about 11 years
    Thanks for the answer. I use it without root, just the relative path File.new('spec/fixtures/images/rails.png') and in my tests it works just fine.
  • Steve
    Steve over 10 years
    You may be thinking "Why use #join, because I know the separator will always be a slash?" - but if you use File join instead of +, you'll get a valid path regardless of whether you forget and put a leading slash before "spec" in the second path.
  • Jwan622
    Jwan622 over 8 years
    What if you used instead of a spec/fixtures/images you used a photo in app/assets/images? I'm using app/assets/images and the photo actually gets uploaded which is strange... and it winds up in my public/system photos which isn't what I want. What can I do?