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 admin: cnetid: admin firstname: Admin lastname: User role: admin rate: 75 email: [email protected] regular: 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." @admin.save_without_session_maintenance @regular.save_without_session_maintenance @edg1 = projects(:edg1) @edg2 = projects(:edg2) end private def login(user, password) get "/login" post_via_redirect "/user_sessions/create", :user_session => { :cnetid => user, :password => password } end
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" end
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" end 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" end end
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.