Wednesday, August 23, 2006

Testing XML-ish stuff in Rails

Hi fellow Railsians,

Today post is in answer to a question from Chris T on the Rails list. Chris asks:
"Probably dead obvious, but are there any assertions for easing testing
of xml output, both for builder templates (for RSS feed -- something
like a version of assert_tag) and for the new restful stuff."

I've seen this question come up several times in the past. The trouble with assert_tag and assert_no_tag is that they are hooked directly to the response object of your controllers. Which means you can only use them in functional or integration tests. You could fake out a response object, but there is a simpler solution, just recreate them. They are essentially a call to the find method of HTML::Document.

Here is what I did: Add the following to the end your test/test_helper.rb:

# Add more helper methods to be used by all tests here...
def assert_xml_tag(xml, conditions)
doc =
assert doc.find(conditions),
"expected tag, but no tag found matching #{conditions.inspect} in:\n#{xml.inspect}"

def assert_no_xml_tag(xml, conditions)
doc =
assert !doc.find(conditions),
"expected no tag, but found tag matching #{conditions.inspect} in:\n#{xml.inspect}"

I chose to use the actual value as the first parameter rather than the expected value because it allows for nicer looking paramter hash values. To use it, use just like assert_tag and assert_no_tag:

def test_xml_correct
assert_xml_tag "", :tag => 'z',
:parent => {:tag => 'y',
:parent => {:tag => 'x'}}

I usually have a default object under test with a single method to output. This allows for a micro-DSL-ish thing to reduce typing overhead:

def assert_render(conditions)
assert_xml_tag @thing.render, conditions


haver said...

Hi Ed!

Cool Blog - sounds interesting, even to a Windows driver /embedded guy like me.

Ed Howland said...

Is this THE Haver? Send me your email to