Testing XML output in rspec and rails

10 December 2007

Testing XML output in rspec and rails

Have you ever tried testing that you get the expected XML output from your rails respond_to block? Did you take the lazy way like me and think it would be as simple as comparing the body of the response with a string matching the expectant XML? Well there is a problem, if you've got multiple attributes on any elements you can't always guarantee the order that the attributes will be output. So lets do it properly, and check it is valid XML and has the attributes we want. I was working on a project needed a graph of election results. The flash graphing object I was using required XML output, which was easy with an appropriate rails respond_to block. However testing it wasn't as straight forward, or so I though initially. After banging my head for an hour or so I realised that the built in have_tag method and support for css selectors would give me everything I needed:

require File.dirname(__FILE__) + '/../../spec_helper'

describe "When viewing an election category as XML" do

  include ModelHelpers

  before(:each) do
    @election = mock_model(Election, setup_election_helper)
    assigns[:election] = @election
    render 'election/show.xml.builder'

  it "should export valid XML for inclusing in flash charts" do
    response.should have_tag("chart[caption='Test Election'][xAxisName='Nominee'][yAxisName='Votes']")
    response.should have_tag("chart set[value=100][label='nominee 1']")
    response.should have_tag("chart set[value=200][label='nominee 2']")
    response.should have_tag("chart set[value=200][label='nominee 3']")
    response.should have_tag("chart set[value=200][label='nominee 4']")
    response.should have_tag("chart set[value=200][label='nominee 5']")            


I'd dabbled with using hpricot to parse the output and traverse through the tree to ensure the elements are all where they should be, but this meets the requirements perfectly. However, it may be worth wrapping the hpricot methods in customer rspec matchers in the long term to make the assertions more readable. For the specific situation though (generating XML to meet the spec of a 3rd party app) I'm happy enough with the result.