Corey InnisCorey Innis
Standup 02/05/2008
edit Posted by Corey Innis on Tuesday February 05, 2008 at 10:42PM

Interesting Things

  • In exploring options for RSpec testing of XML responses, one project decided a custom XPath matcher would do the trick nicely:

    items = Item.find(:all)
    get :index
    
    
    response.body.should     have_nodes("//items/item", items.size)
    response.body.should     have_xpath("//items/item[ position() = 1 and @id = '0001' ]")
    response.body.should_not have_xpath("//bogus")
    

    Some other possibilities:

    • Hashes...

      items = Item.find(:all)
      get :index
      
      
      hash = Hash.from_xml(response.body)
      hash['ancestor']['parent']['items']['item'].size.should == items.size
      hash['ancestor']['parent']['items']['item'][0]['id'].should == '0001'
      hash['ancestor']['parent']['bogus'].should be_nil
      
    • Hpricot...

      items = Item.find(:all)
      get :index
      
      
      doc = Hpricot(response.body)
      doc.search("//items/item").size.should == items.size
      doc.at("//items/item[ @id = '0001' ]").position.should == 1
      doc.at("//bogus").should be_nil
      
    • assert_select from Rail's Test::Unit (using CSS-style selectors)...

      items = Item.find(:all)
      get :index
      
      
      assert_select("items > item", :count => 5)
      assert_select("items > item:nth-child(1)[id=?]", '0001')
      assert_select("bogus", false)
      

    What are your favorite techniques for asserting XML/XPath?

  • Something to consider when test-driving controller code:

    You're working with ActionController::TestResponse. So, response.success?, response.redirect?, etc. are available for you there (since they are defined on TestResponse), but not in your actual controllers. That is, things blow up if you try to use @response.success? in your application,

    e.g. to determine whether or not to store the current URL and redirect there after a login.

Comments

  1. Hualing Hualing on February 06, 2008 at 01:28AM

    I always use ruby more for applications. I've read somewhere that they're coming up with a more advanced and stable version of it. Any thoughts?

  2. James Deville James Deville on February 06, 2008 at 03:08AM

    We use a custom XPath matcher, based on the link you provided, using Hpricot to do the parsing. I found a decent speed improvement by using Hpricot instead of REXML. Also, if you are considering assert_select, but want to use RSpec, then why wouldn't you use have_tag, it's just a wrapper around assert_select.

  3. Corey Corey on February 06, 2008 at 05:39PM

    @James - Great feedback. We actually also have at least one project using custom matchers backed by Hpricot, but they're less complete (and less publicly accessible) than the one linked above. Good suggestion with Rspec's have_tag; example set ported to have_tag below. Keep in mind that you take a performance hit when using have_tag (and by extension assert_select) since Rails loads the entire DOM.

        items = Item.find(:all)
        get :index
    
        response.should have_tag("items > item", :count => 5)
        response.should have_tag("items > item:nth-child(1)[id=?]", '0001')
        response.should have_tag("bogus", false)
    
  4. Corey Corey on February 06, 2008 at 05:44PM

    And, I guess this would be nicer for that last one... response.should_not have_tag("bogus")