Rails Integration Tests

After unit tests, for me, the important tests are integration tests. This is where I can test logging in and checking authorizations and calculations. They are a bit more involved, but not too difficult once you get the hang of them.

My app authenticates users using ldap. One great advantage I have is that I’m in charge of the ldap system as well. So I just made a couple of ldap users, who were NOT allowed to login to our normal system, and used them to test that logins were working.

Users fixture

# These two accounts have been set up as 
#non login accounts on the server for testing purposes
  cnetid: admin
  firstname: Admin 
  lastname: User
  role: admin
  rate: 75
  email: [email protected]
  cnetid: regular
  firstname: Regular
  lastname: User
  role: user
  rate: 50
  email: [email protected]

All of my integration tests have a setup and login (private) method.
They look like this:

  def setup
    @admin = users(:admin)
    @regular = users(:regular)
    # Need the without_session_maintenance here or get an error with authlogic
    # "ActionDispatch::ClosedError: Cannot modify cookies because it was closed."
    @edg1 = projects(:edg1)
    @edg2 = projects(:edg2)

  def login(user, password)
    get "/login"
    post_via_redirect "/user_sessions/create", 
     :user_session => { :cnetid => user, :password => password }

Once I have that setup, I can start writing my tests. Basically, all I do in each test is login with one of my valid users and then run my assertions. As an example, in the following test, I’m logging in as a regular user and then I’m going to try to edit the profile of the admin user. Since I have my authorization rules set so that users (who are not admins) can only edit their own profile, this should not be allowed. If a user does try to edit someone else’s profile, they should be redirected to the root_path.

  test "user trying to edit another user profile" do
    login(:regular, 'password')
    get_via_redirect (edit_user_path(id = @admin.id))
    assert_equal root_path, path, "User allowed to edit another user's profile"

I have a bunch of tests that login as my regular user and my admin and try to edit various things.

A more elaborate integration test is one that calculates expenses for a given project in a given month. That test looks like this:

  test "calculate monthly report" do
    login(:admin, 'password')
    get_via_redirect new_timesheet_path
    timesheet1 = Timesheet.new(:user_id => @regular.id, :monthyear => '2011-10-01', 
                :entries_attributes => {"0" => { :project_id => @atlas.id, :hours => 10 }, 
                                        "1" => { :project_id => @cdf.id, :hours => 20 }})
    assert timesheet1.save, "Didn't save first timesheet"
    timesheet2 = Timesheet.new(:user_id => @admin.id, :monthyear => '2011-10-01',
                :entries_attributes => {"0" => {:project_id => @cdf.id, :hours => 100 },
                                        "1" => {:project_id => @atlas.id, :hours => 50 }})
    assert timesheet2.save, "Didn't save second timesheet"
    # Add another timesheet in a different month to make sure the calculation is
    # only using ones from the month selected
    timesheet3 = Timesheet.new(:user_id => @regular.id, :monthyear => '2011-11-01',
                :entries_attributes => {"0" => {:project_id => @cdf.id, :hours => 1000 },
                                        "1" => {:project_id => @atlas.id, :hours => 1000 }})
    assert timesheet3.save, "Didn't save third timesheet"
    get_via_redirect monthly_report_projects_path(:month => '2011-10-01')
    assert_not_nil assigns(:projects), "@projects is nil"

    assert_select "table" do
      assert_select "tr" do
        assert_select "td", "ATLAS", "no ATLAS line"
        assert_select "td", "123456-6200", "no ATLAS account"
        assert_select "td", "$4,250.00", "wrong ATLAS value"
      assert_select "tr" do
        assert_select "td", "CDF", "no CDF line"
        assert_select "td", "234567-6200", "no CDF account"
        assert_select "td", "$8,500.00", "wrong CDF value"

In line 2, I login as my admin user. Then I get a new timesheet. Lines 3-19 are just me generating three timesheets. I made sure that I got timesheets from both users and one from a different month.

Line 21 goes to the monthly_reports page and gets the info for the month starting on 2011-10-01. The assertion in line 22 makes sure that @projects is not empty. Next, I look at the html on the page that was rendered. I’m looking for a table and then a row. In lines 26-28, I’m looking for a td with the name of the project (ATLAS), then a td with the project account-subaccount info. Line 28 has the most important assertion, it’s checking that the total displayed is equal to the value I calculated that the account should be charged for that month, based on the timesheets I entered earlier. Lines 30-34 just repeat the process with the other account number.