Initial code for JUnit output

This commit is contained in:
Michael Miller 2019-03-23 15:31:53 -06:00
parent 4890cafefa
commit 3776cd917e
7 changed files with 203 additions and 0 deletions

View file

@ -0,0 +1,26 @@
module Spectator::Formatting
private struct ErrorJUnitTestCase
def initialize(@result : ErroredResult)
end
def to_xml(xml : ::XML::Builder)
xml.element("testcase",
name: @result.example,
status: @result,
time: @result.elapsed.total_seconds,
classname: classname,
assertions: @result.expectations.size) do
xml.element("error", message: @result.error.message, type: @result.error.class)
@result.expectations.each_unsatisfied do |expectation|
xml.element("failure", message: expectation.actual_message) do
# TODO: Add values as text to this block.
end
end
end
end
private def classname
"TODO"
end
end
end

View file

@ -0,0 +1,25 @@
module Spectator::Formatting
private struct FailureJUnitTestCase
def initialize(@result : FailedResult)
end
def to_xml(xml : ::XML::Builder)
xml.element("testcase",
name: @result.example,
status: @result,
time: @result.elapsed.total_seconds,
classname: classname,
assertions: @result.expectations.size) do
@result.expectations.each_unsatisfied do |expectation|
xml.element("failure", message: expectation.actual_message) do
# TODO: Add values as text to block.
end
end
end
end
private def classname
"TODO"
end
end
end

View file

@ -0,0 +1,52 @@
require "xml"
module Spectator::Formatting
# Formatter for producing a JUnit XML report.
class JUnitFormatter < Formatter
# Name of the JUnit output file.
private JUNIT_XML_FILE = "output.xml"
# Name of the top-level test suites block.
private NAME = "AllTests"
# Creates the formatter.
# By default, output is sent to STDOUT.
def initialize(output_dir : String)
path = File.join(output_dir, JUNIT_XML_FILE)
@io = File.open(path, "w")
@xml = XML::Builder.new(@io)
end
# Called when a test suite is starting to execute.
def start_suite(suite : TestSuite)
@xml.start_document(encoding: "UTF-8")
end
# Called when a test suite finishes.
# The results from the entire suite are provided.
def end_suite(report : Report)
@xml.element("testsuites",
tests: report.example_count,
failures: report.failed_count,
errors: report.error_count,
time: report.runtime.total_seconds,
name: NAME) do
report.group_by(&.example.source.path).each do |path, results|
JUnitTestSuite.new(path, results).to_xml(@xml)
end
end
@xml.end_document
@xml.flush
@io.close
end
# Called before a test starts.
def start_example(example : Example)
end
# Called when a test finishes.
# The result of the test is provided.
def end_example(result : Result)
end
end
end

View file

@ -0,0 +1,26 @@
module Spectator::Formatting
# Selector for creating a JUnit test case based on a result.
private module JUnitTestCase
extend self
# Creates a successful JUnit test case.
def success(result)
SuccessfulJUnitTestCase.new(result.as(SuccessfulResult))
end
# Creates a failure JUnit test case.
def failure(result)
FailureJUnitTestCase.new(result.as(FailedResult))
end
# Creates an error JUnit test case.
def error(result)
ErrorJUnitTestCase.new(result.as(ErroredResult))
end
# Creates a skipped JUnit test case.
def pending(result)
SkippedJUnitTestCase.new(result.as(PendingResult))
end
end
end

View file

@ -0,0 +1,36 @@
module Spectator::Formatting
# Mapping of a single spec file into a JUnit test suite.
private struct JUnitTestSuite
# Creates the JUnit test suite.
# The *path* should be the file that all results are from.
# The *results* is a subset of all results that share the path.
def initialize(@path : String, results : Array(Result))
@report = Report.new(results)
end
# Generates the XML for the test suite (and all nested test cases).
def to_xml(xml : ::XML::Builder)
xml.element("testsuite",
tests: @report.example_count,
failures: @report.failed_count,
errors: @report.error_count,
skipped: @report.pending_count,
time: @report.runtime.total_seconds,
name: name,
package: package) do
@report.each do |result|
test_case = result.call(JUnitTestCase) { |r| r }
test_case.to_xml(xml)
end
end
end
private def name
"TODO"
end
private def package
"TODO"
end
end
end

View file

@ -0,0 +1,19 @@
module Spectator::Formatting
private struct SkippedJUnitTestCase
def initialize(@result : PendingResult)
end
def to_xml(xml : ::XML::Builder)
xml.element("testcase",
name: @result.example,
status: @result,
classname: classname) do
xml.element("skipped")
end
end
private def classname
"TODO"
end
end
end

View file

@ -0,0 +1,19 @@
module Spectator::Formatting
private struct SuccessfulJUnitTestCase
def initialize(@result : SuccessfulResult)
end
def to_xml(xml : ::XML::Builder)
xml.element("testcase",
name: @result.example,
status: @result,
time: @result.elapsed.total_seconds,
classname: classname,
assertions: @result.expectations.size)
end
private def classname
"TODO"
end
end
end