Index: lib/test/unit/autorunner.rb =================================================================== --- lib/test/unit/autorunner.rb (revision 22625) +++ lib/test/unit/autorunner.rb (working copy) @@ -41,6 +41,11 @@ require 'test/unit/ui/tk/testrunner' Test::Unit::UI::Tk::TestRunner end, + :xml => proc do |r| + require 'test/unit/ui/xml/testrunner' + Test::Unit::UI::Xml::TestRunner + end, + } OUTPUT_LEVELS = [ Index: lib/test/unit/ui/xml/xml_report.dtd =================================================================== --- lib/test/unit/ui/xml/xml_report.dtd (revision 0) +++ lib/test/unit/ui/xml/xml_report.dtd (revision 0) @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + Index: lib/test/unit/ui/xml/testrunner.rb =================================================================== --- lib/test/unit/ui/xml/testrunner.rb (revision 0) +++ lib/test/unit/ui/xml/testrunner.rb (revision 0) @@ -0,0 +1,141 @@ +#-- +# +# Author:: Flavio Castelli. +# Copyright:: Copyright (c) 2009 Flavio Castelli. All rights reserved. +# License:: Ruby license. + +require 'test/unit/ui/testrunnermediator' +require 'test/unit/ui/testrunnerutilities' +require 'test/unit/ui/console/testrunner' + +require 'rexml/document' + +include REXML + +class Test::Unit::TestResult + attr_reader :failures, :errors +end + +module Test + module Unit + module UI + module Xml + + # Behaves like Test::Unit::UI::Console::TestRunner but can create an xml + # file containing the unit test results. + # The xml file name is defined using an environment variable called _XML_OUTPUT_FILE_ + # + # The output xml can be validated using the following DTD: + # + # + # + # + # + # + # + # + # + # + # + # + # + # + # + + class TestRunner < Test::Unit::UI::Console::TestRunner + + # Creates a new TestRunner for running the passed + # suite. If quiet_mode is true, the output while + # running is limited to progress dots, errors and + # failures, and the final result. io specifies + # where runner output should go to; defaults to + # STDOUT. + def initialize(suite, output_level=NORMAL, io=STDOUT) + super(suite, output_level, io) + end + + def finished(elapsed_time) + super(elapsed_time) + + xml_file_path = ENV["XML_OUTPUT_FILE"] + + if xml_file_path.nil? + nl + output("Provide XML_OUTPUT_FILE environment variable in order to save unit test result to file") + nl + else + nl + File.open(xml_file_path,'w') {|file| file.write(generate_xml(elapsed_time)) } + output("Xml summary saved: #{xml_file_path}") + nl + end + end + + private + + # Generates the xml file containing the unit test stats + def generate_xml(elapsed_time) + xml = Document.new + unit_test = Element.new "unit_test" + unit_test.add_attributes( {"tests" => @result.run_count.to_s, + "assertions" => @result.assertion_count.to_s, + "failures" => @result.failures.size.to_s, + "errors" => @result.errors.size.to_s, + "elapsed_time" => elapsed_time.to_s}) + xml.elements << unit_test + + failures = Element.new("failures") + @result.failures.each do |failure| + failure_element = Element.new("failure") + + message = failure_element.add_element("message") + message.text = failure.message + + method_name = failure_element.add_element "method" + class_name = failure_element.add_element "class" + + failure.test_name =~ /(\w+\_\w+)\((.+)\)/ + method_name.text = $1 + class_name.text = $2 + + location = failure_element.add_element("location") + location.text = failure.location + + failures.elements << failure_element + end + unit_test.elements << failures + + errors = Element.new("errors") + @result.errors.each do |error| + error_element = Element.new("error") + + exception = error_element.add_element("exception") + exception.text = error.exception + + method_name = error_element.add_element "method" + class_name = error_element.add_element "class" + + error.test_name =~ /(\w+\_\w+)\((.+)\)/ + method_name.text = $1 + class_name.text = $2 + + errors.elements << error_element + end + unit_test.elements << errors + + xml + end + + end + end + end + end +end + +if __FILE__ == $0 + Test::Unit::UI::Xml::TestRunner.start_command_line_test +end