Integration Testing

Integration testing is the most complicated testing Rails supports directly. It tests complete requests coming in from the outside, running through routing, controllers, models, the database, and even views. Rails does not generate any integration tests by default, as creating them requires detailed knowledge of the complete application and what it is supposed to do. Integration tests are stored in tests/integration and look much like the classes for other kinds of tests. They call similar methods and also make assertions, but the assertions are different and the flow can cover multiple interactions, as Example 12-15 demonstrates.

Example 12-15. An integration test that tries adding a student

require 'test_helper'

# Integration tests covering the manipulation of student objects

class StudentsTest < ActionController::IntegrationTest

  def test_adding_a_student
    # get the new student form
    get '/students/new' # could be new_students_path

    # check there are boxes to put the name in
    # trivial in our case, but illustrates how to check output HTML
    assert_select "input[type=text][name='student[given_name]']"
    assert_select "input[type=text][name='student[family_name]']"

    assert_difference('Student.count') do
      post '/students/create', :student => {
        :given_name => "Fred",
        :family_name => "Smith",
        :date_of_birth => "1999-09-01",
        :grade_point_average => 2.0,
        :start_date => "2008-09-01"
      }
    end

    assert_redirected_to "/students/#{assigns(:student).id}"
    follow_redirect!

    # for completeness, check it's showing some of our data
    assert_select "p", /Fred/
    assert_select "p", /2008-09-01/
  end

end

Instead of calling the create method directly, as the functional tests would do, test_adding_a_student starts by using the get method—with a URI fragment rather than a function name—to retrieve the form needed for adding a student.

Next, the method examines that form with assert_select, one of Rails’ methods for testing HTML documents to see if they contain what you expect them to contain. In the first of those two statements, assert_select tries to match the pattern:

input[type=text][name='student[given_name]']

That would be an input element with a type attribute set to text and a name attribute set to student[given_name]. (The single quotes are necessary to keep the [ and ] from causing trouble with the match pattern syntax.) The form should match that, as it contains:

<input id="student_given_name" name="student[given_name]" size="30"
 type="text" />

Once Rails has performed those assertions, it moves to actually submitting a new student. There’s no way (yet) for Rails to actually fill in the form and press the submit button, but the test does the next best thing, issuing a POST request that reflects what the form would have done, from inside of an assert_difference call that looks for an added student:

assert_difference('Student.count') do
      post '/students/create', :student => {
        :given_name => "Fred",
        :family_name => "Smith",
        :date_of_birth => "1999-09-01",
        :grade_point_average => 2.0,
        :start_date => "2008-09-01"
      }
    end

Again, the call is to a URL, not to a method name, though this post call includes parameters designed to reflect the structure that would be returned by the form Rails generated. The page showing this student, Fred Smith, should come back from Rails for display through a redirect, so the next assertion watches for that:

assert_redirected_to "/students/#{assigns(:student).id}"

The assertion can grab the id value for the new student, whatever it is, from the controller, using the all-powerful assigns method. If it gets sent somewhere other than it expects, it will report failure.

The next call is fairly self-explanatory:

follow_redirect!

There’s one last step needed here: checking that response to see if it reflects expectations. Following the redirect lets the test continue to the final part of the interaction, in which Rails shows off the newly created student. Here, the test uses more assert_select statements in a slightly different syntax:

assert_select "p", /Fred/
assert_select "p", /2008-09-01/

When given a string and a regular expression as arguments, assert_select will look for elements of the type given in the string (here, p) that contain values matching the expression. Appendix C has more details on regular expressions, but the first of these is just the string Fred, while the other is an escaped version of 2008-09-01. These are, of course, the values that the test set earlier, and they should appear in the document. Will they?

$ rake test:integration
(in /Users/simonstl/Documents/RailsOutIn/current/code/ch12/students005)
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test
"/Library/Ruby/Gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader.rb"
"test/integration/students_test.rb"
Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader
Started
.
Finished in 0.368834 seconds.

1 tests, 7 assertions, 0 failures, 0 errors

It all worked.

Creating useful integration tests is difficult. It requires plotting a path through your application, deciding which pieces are relevant, and which are not. As your application grows in complexity and interdependence, they may become critical, though smaller applications can often do without them for a long while.

Note

If assert_select isn’t enough for your view-testing experiments, Rails offers many more options, including assert_tag, assert_no_tag, assert_dom_equal, assert_dom_not_equal, assert_select_encoded, and assert_select_rjs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset