Testing/Convert-NAVResultsToXUnit.ps1

function Convert-NAVResultsToXUnit {
    Param(
        [Parameter(Mandatory=$true)]
        [string]$NAVResultsPath,
        [Parameter(Mandatory=$true)]
        [string]$XUnitPath
    )

    if (Test-Path $XUnitPath) {
    Remove-Item $XUnitPath
    }

    [xml]$TestResultsXml = Get-Content $NAVResultsPath
    $TestResults = @()
    foreach ($TestResultNode in $TestResultsXml.SelectNodes('/TestResults/TestResult')) {
        $TestResult = New-Object System.Object
        foreach ($TestResultElement in $TestResultNode.ChildNodes) {
            $TestResult | Add-Member -MemberType NoteProperty -Name $TestResultElement.Name -Value $TestResultElement.InnerText
        }
        $TestResult | Add-Member -MemberType NoteProperty -Name Duration -Value (Convert-ExecutionTimeToDuration $TestResult.ExecutionTime)
        $TestResults += $TestResult    
    }

    $XmlWriter = New-Object System.Xml.XmlTextWriter($XUnitPath,$null)
    $XmlWriter.Formatting = 'Indented'
    $XmlWriter.Indentation = '4'

    $XmlWriter.WriteStartDocument()
    $XmlWriter.WriteStartElement('assemblies')

    $XmlWriter.WriteStartElement('assembly')
    $XmlWriter.WriteAttributeString('name','Dynamics NAV')
    $XmlWriter.WriteAttributeString('config-file','')
    $XmlWriter.WriteAttributeString('test-framework','')
    $XmlWriter.WriteAttributeString('environment','')
    $XmlWriter.WriteAttributeString('run-date',[DateTime]::Today.ToString('yyyy-MM-dd'))
    $XmlWriter.WriteAttributeString('run-time',[DateTime]::Now.ToString('HH:mm:ss'))
    $XmlWriter.WriteAttributeString('time',[Math]::Round(($TestResults | Measure-Object -Property Duration -Sum).Sum / 1000,0))
    $XmlWriter.WriteAttributeString('total',($TestResults).Count)
    $XmlWriter.WriteAttributeString('passed',($TestResults | where Result -eq Passed).Count)
    $XmlWriter.WriteAttributeString('failed',($TestResults | where Result -eq Failed).Count)
    $XmlWriter.WriteAttributeString('skipped',($TestResults | where Result -eq Skipped).Count)

    foreach ($CUId in ($TestResults | select CUId -Unique).CUId) {
        $XmlWriter.WriteStartElement('collection')
        $XmlWriter.WriteAttributeString('name',($TestResults | where CUId -eq $CUId | select CUName -Unique).CUName)
        $XmlWriter.WriteAttributeString('time',[Math]::Round(($TestResults | where CUId -eq $CUId | Measure-Object -Property Duration -Sum).Sum / 1000,0))
        $XmlWriter.WriteAttributeString('total',($TestResults | where CUId -eq $CUId).Count)
        $XmlWriter.WriteAttributeString('passed',($TestResults | where CUId -eq $CUId | where Result -eq Passed).Count)
        $XmlWriter.WriteAttributeString('failed',($TestResults | where CUId -eq $CUId | where Result -eq Failed).Count)
        $XmlWriter.WriteAttributeString('skipped',($TestResults | where CUId -eq $CUId | where Result -eq Skipped).Count)

        foreach ($TestResult in ($TestResults | where CUId -eq $CUId)) {
            $XmlWriter.WriteStartElement('test')
            $XmlWriter.WriteAttributeString('name',$TestResult.FName)
            $XmlWriter.WriteAttributeString('type','')
            $XmlWriter.WriteAttributeString('method',$TestResult.FName)
            $Xmlwriter.WriteAttributeString('time',[Math]::Round($TestResult.Duration / 1000,0))
            switch ($TestResult.Result) {
                'Passed' {$XmlWriter.WriteAttributeString('result','Pass'); break}
                'Failed' {$XmlWriter.WriteAttributeString('result','Fail'); break}
                'Skipped' {$XmlWriter.WriteAttributeString('result','Skip'); break}
            }

            if ($TestResult.Result -eq 'Failed') {
                $XmlWriter.WriteStartElement('failure')
                $XmlWriter.WriteAttributeString('exception-type',$TestResult.ErrorCode)
                $XmlWriter.WriteStartElement('message')
                $XmlWriter.WriteCData($TestResult.ErrorMessage)
                $XmlWriter.WriteEndElement() #message element
                $XmlWriter.WriteStartElement('stack-trace')
                $XmlWriter.WriteCData($TestResult.CallStack.Replace('\',[Environment]::NewLine))
                $XmlWriter.WriteEndElement() #stack-trace element
                $XmlWriter.WriteEndElement() #failure element
            }

            $XmlWriter.WriteEndElement() #test element
        }

        $XmlWriter.WriteEndElement() #collection element
    }

    $XmlWriter.WriteEndElement() #assembly element
    $XmlWriter.WriteEndElement() #assemblies element
    $XmlWriter.WriteEndDocument()

    $XmlWriter.Flush()
    $XmlWriter.Close()
}

function Convert-ExecutionTimeToDuration {
    Param(
        [string]$ExecutionTime
    )
    [int]$Seconds = 0
    [int]$Milliseconds = 0

    if ($ExecutionTime.Contains(' second')) {
        $Seconds = [Int32]::Parse($ExecutionTime.Substring(0,$ExecutionTime.IndexOf('second') - 1))
        $ExecutionTime = $ExecutionTime.Substring($ExecutionTime.IndexOf('second') + 7)
    }

    $ExecutionTime = $ExecutionTime.TrimStart(' ')

    if ($ExecutionTime.Contains('millisecond')) {
        $Milliseconds = [Int32]::Parse($ExecutionTime.Substring(0,$ExecutionTime.IndexOf('millisecond') - 1))
    }

    $Seconds * 1000 + $Milliseconds
}

Export-ModuleMember -Function Convert-NAVResultsToXUnit