XML round-trip testing for Rails resources

I’ve recently started to add XML support to a Rails application, meaning that the application provides data in XML format, if the request asks for it, and it understands XML data on create or update.

To keep the application as well as myself sane, I’ve written a test that ensures the round trip of getting XML and updating an object by sending XML works. This is only a very basic test and there surely is more that can and should be tested.

class XmlRoundtripTest < ActionController::IntegrationTest

  RESOURCES = [
    :people, :things
  ]
  fixtures :stuff, *RESOURCES

  def self.assert_roundtrippability_for(*resources)
    resources.each do |resource|
      define_method("test_xml_roundtrip_for_#{resource}") do
        @user = user
        @user.logs_in

        xml = @user.gets_xml(resource)
        @user.changes_object_name!(xml)

        old_version = @user.extracts_lock_version(xml)
        @user.sends_xml(xml, resource)

        # Make sure that the resource was really updated
        new_version = @user.extracts_lock_version(@user.gets_xml(resource))
        assert_equal(old_version + 1, new_version)
      end
    end
  end

  assert_roundtrippability_for *RESOURCES

  def user
    open_session do |user|
      def user.gets_xml(resources, id = 1)
        get "/#{resources}/#{id}.xml"
        assert_response :success
        @response.body
      end

      def user.sends_xml(xml, resources, id = 1)
        put "/#{resources}/#{id}.xml", xml, :content_type => 'application/xml'
        assert_response :success
        @response.body
      end

      def user.changes_object_name!(xml)
        # arbitrarily change an attribute we know is there
        xml.gsub!(%r{<name>(.*?)</name>}, '<name>X\1Y</name>')
      end

      def user.extracts_lock_version(xml)
        xml =~ %r{<lock-version>(\d+)</lock-version>}
        $1.to_i
      end
    end
  end
end

Leave a Reply

Your email address will not be published. Required fields are marked *