Apr 9, 2009

Testing Attachment Fu in Rails Test Unit

Whether you're using standard Test Unit or Shoulda, you should be testing models. But if a User model has to have a Photo, how do you set up a unit test to make sure it passes? I've read blog posts and forums threads on the issue but never found anything comprehensive enough for a entry-level rails tester to understand. So, with that in mind, read on for a quick tutorial.


I'm using Shoulda so my tests are geared for that syntax. If you're using Test Unit, feel free to modify accordingly. The meat of the answer is still the same.

First of all, let's assume you're in the test/unit/user.rb file doing your unit test. Your file starts off looking like this:
require File.join(File.dirname(__FILE__),"..","test_helper")

class UserTest < ActiveSupport::TestCase
end


You'll want to add your context block, setup block, and an assertion too.


context "A new user with a valid photo" do
setup do
@user = User.create(:email => "test@example.com", :login => "test", :password => "password123", :password_confirmation => "password123")
end

should "be a valid user" do
assert(@user.valid?)
end
end


Running the above test won't work if you're requiring a photo because you haven't actually set one up. To do that you'll have to use create the photo in the test like this:

@photo = Photo.create(:uploaded_data => fixture_file_upload("/files/mugshot.png",'image/png')


The tricky part is that the fixture_file_upload is a part of ActionController::TestProcess. So you'll need to include it for it to work. The final user.rb will therefore look like this:

require File.join(File.dirname(__FILE__),"..","test_helper")

class UserTest < ActiveSupport::TestCase
include ActionController::TestProcess
context "A new user with a valid photo" do
setup do
@photo = Photo.create(:uploaded_data => fixture_file_upload("/files/mugshot.png",'image/png'))
@user = User.create(:email => "test@example.com", :login => "test", :password => "password123", :password_confirmation => "password123", :photo => [@photo])
end

should "be a valid user" do
assert(@user.valid?)
end
end
end


Now when you run your test, it should pass:
ruby test/unit/user.rb

Started
.
Finished in 0.196 seconds.

1 tests, 1 assertions, 0 failures, 0 errors


A few things to look out for:

  • - The above assumes a User has many Photos which is why it's photos => [@photo] and not photo => @photo.

  • - You'll need to create a file called mugshot.png and put it in the test/fixtures/files directory (which you probably need to create)

  • - I'm using Shoulda, if you use straight test::unit or rspec, you'll need to change things appropriately.

  • - My example also assumes the only things required in your user model is the email, login, password, and photo. Adjust accordingly.


Hopefully the above works for you. Now that you're validating attachments correctly there's no reason not to do more testing!

2 comments:

  1. Thanks. Works beautifully with one minor correction:

    The path of the file in: fixture_file_upload("/files/mugshot.png",'image/png')) should have no leading slash. It should be: "files/mugshot.png"

    ReplyDelete
  2. It actually worked either way for me so if you have trouble with the leading slash then I'd say go ahead and remove it..

    ReplyDelete