advertisement

Print

Rails Testing: Not Just for the Paranoid
Pages: 1, 2, 3, 4, 5

Time to move on

You're most of the way to having a functional little tag search together. It's not particularly elegant, but will suffice for showing some functional testing in action. I'll leave it as an exercise to the reader to hook up a proper view for this, but include my minimalistic one in the source package for Tasty.

The key thing to take away from functional tests is that they allow you to verify that your application is responding as expected to various requests, and that they map to your controller actions, providing a safety net for them and making it easier to refactor things down the line.

Integration testing, for the high-level stuff

Getting an incredibly realistic use case for integration testing into Tasty at this point would be tricky. The reason for this is that integration tests often take the form of "big picture" user stories. An ideal case might be something like "James logs in, James purchases the very last super cool robot. Sam tries to buy a super cool robot, but can't because James already scooped it up". We don't quite have room in this article to expand Tasty to that level.

That having been said, integration testing can be quite useful for when you're dealing with session data, even for simple things.

Anyone who's messed with testing sessions by hand in a browser without some extra supporting apps probably has inevitably felt some considerable pain.

We're going to add a simple feature to Tasty that lets users indicate which entry in the system is their "favorite." What this will demonstrate is that we can create two separate sessions in our tests which do not interfere with each other.

Let's start by generating some code:

 $ script/generate integration_test stories

The following integration test shows how to build a custom user object with some helper methods, borrowing a trick from Agile Web Development With Rails.

test/integration/stories_test.rb
require "#{File.dirname(__FILE__)}/../test_helper" 

class StoriesTest < ActionController::IntegrationTest
  def test_users_have_separate_favorite_entries

    populate_entries

    greg  = regular_user
    andra = regular_user

    greg.gets_a_random_favorite_entry

    greg_first = greg.favorite_entry

    andra.gets_a_random_favorite_entry

    # make sure session does not change after other user gets an entry.
    assert_equal greg_first, greg.favorite_entry
  end

  def regular_user
    open_session do |user|
      def user.favorite_entry
        session[:favorite]
      end

      def user.gets_a_random_favorite_entry
        get "/entries/random_favorite" 
        assert_response :success
        assert Entry.find(session[:favorite])
      end
    end
  end

  def populate_entries
    %w[abc.com def.org hij.net].each do |u|
      Entry.create(:url => u)
    end
  end

end

Our first failure happens as expected; it can't find the random_favorite action.

Expected response to be a <:success>, but was <404>

The following chunk of code should get you passing the tests, but be sure to add a view, even if it's empty.

app/controllers/entries_controller.rb
  def random_favorite
    session[:favorite] = rand(Entry.count) + 1
  end

From here, you'd probably want to consider moving this kind of feature down into the User model, after adding a way to login and identify yourself to Tasty. For now, it suffices as a way to show how you can build tests that run with independent sessions for your applications.

Another thing that integration tests are important for, as you get into more advanced situations, is for testing any interesting logic you may have in your routes. Functional tests bypass a lot of the routing stuff, so integration tests are about the only way to test them effectively.

I didn't bother building a view for this new feature, but you could probably just add something like a favorite? method to Entry which inspects the session data and does some interesting formatting in your view as needed.

The End of the Road, But Only the Tip of the Iceberg

Rails Testing is a very big topic. I hope that this article has at least shown by example the bare minimum necessary for you to know what the various kinds of tests are used for, and how to get everything hooked up. There are plenty of folks out there writing Rails apps that don't fire up a browser until they're ready to work on design. I'm not quite that macho, but I do enjoy spending more time in my preferred programming environment than in the browser.

As you get more into testing, you'll find no shortage of interesting topics that I omitted from this article. I recommend doing a deep dive into the resources scattered across the blogosphere, because in the end, this stuff really does make you more productive.

If you'd like to see tasty in its present state, please do download the latest source , and if you'd rather start with the same base I used to create this article, you can grab that instead.

Thanks for taking another deep dive with me, and have fun writing those tests!

Gregory Brown is a New Haven, CT based Rubyist who spends most of his time on free software projects in Ruby. He is the original author of Ruby Reports.


Return to O'Reilly Ruby.