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_nilHpricot…
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_nilassert_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.
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?
February 6, 2008 at 1:28 am
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.
February 6, 2008 at 3:08 am
@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)
February 6, 2008 at 5:39 pm
And, I guess this would be nicer for that last one… `response.should_not have_tag(“bogus”)`
February 6, 2008 at 5:44 pm