Write-JojobaXml.ps1

<#
 
.SYNOPSIS
Converts Jojoba test case objects to a jUnit XML file Jenkins can understand.
 
.DESCRIPTION
Jenkins is best used with a jUnit XML file to provide further information on why tests have passed, failed, or been skipped. This function provides that translation.
 
.PARAMETER Test
One or more Jojoba test case outputs. This would normally be generated by Start-Jojoba and sent here by Publish-Jojoba.
 
.PARAMETER OutputPath
Override the output path. It defaults to ".\Jojoba.xml".
 
.EXAMPLE
[PSCustomObject] @{
    Suite = "Suite"
    Timestamp = Get-Date
    Time = 0
    ClassName = "Test"
    Name = "Server1"
    Result = "Pass"
    ErrorMessage = New-Object Collections.ArrayList
    Data = New-Object Collections.ArrayList
} | Write-JojobaXml
 
#>


function Write-JojobaXml {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline=$true)]
        $Test,
        $OutputPath = ".\Jojoba.xml"
    )

    begin {
        $xmlDocument = New-Object System.Xml.XmlDocument
        $xmlDocument.LoadXml('<testsuites></testsuites>')

        $templateSuite = New-Object System.Xml.XmlDocument
        $templateSuite.LoadXml('<testsuite name="" tests="0"></testsuite>')
        $templateCase = New-Object System.Xml.XmlDocument
        $templateCase.LoadXml('<testcase classname="" name="" timestamp="" time="0"></testcase>')
        $templateFailure = New-Object System.Xml.XmlDocument
        $templateFailure.LoadXml('<failure message=""></failure>')
        $templateSkipped = New-Object System.Xml.XmlDocument
        $templateSkipped.LoadXml('<skipped message=""></skipped>')
    }

    process {
        foreach ($suite in ($Test | Group-Object Suite | Sort Case)) {
            $xmlSuite = $xmlDocument.ImportNode($templateSuite.testsuite, $false)
            $xmlSuite.name = $suite.Name # From Group-Object
            $xmlSuite.tests = $suite.Group.Count.ToString()

            foreach ($case in $suite.Group) {
                $xmlCase = $xmlDocument.ImportNode($templateCase.testcase, $false)
                $xmlCase.timestamp = $case.Timestamp.ToString()
                $xmlCase.time = $case.Time.ToString()

                $xmlCase.classname = $case.Suite + "." + $case.ClassName
                $xmlCase.name = $case.Name

                if ($case.Result -eq "Fail") {
                    $xmlFailure = $xmlDocument.ImportNode($templateFailure.failure, $false)
                    if ($case.Message) {
                        $xmlFailure.message = $case.Message.ToString()
                    }
                    if ($case.Data) {
                        $xmlFailure.InnerText = $case.Data.ToString()
                    }

                    [void] $xmlCase.AppendChild($xmlFailure)
                } elseif ($case.Result -eq "Skip") {
                    $xmlSkipped = $xmlDocument.ImportNode($templateSkipped.skipped, $false)
                    if ($case.Message) {
                        $xmlSkipped.message = $case.Message.ToString()
                    }
                    if ($case.Data) {
                        $xmlSkipped.InnerText = $case.Data.ToString()
                    }

                    [void] $xmlCase.AppendChild($xmlSkipped)
                }
                [void] $xmlSuite.AppendChild($xmlCase)
            }

            [void] $xmlDocument.ChildNodes.AppendChild($xmlSuite)
        }
    }

    end {
        $xmlDocument.Save($OutputPath)
    }
}