We've just made the jump to JetBrains DotCover, and I'm reasonably impressed by the command line implementation. I think its worth mentioning that the Developers's are very happy with the Visual Studio integration, but that's not a part of the world I inhabit so I couldn't comment.
Supporting DotCover in our build pipeline was almost painless. The only part where I struggled was on the DotCover command line documentation. It took me a good while to realise that TargetArguments is where I specify the command line arguments used by the test-runner. In our case, the actual MSTest command line arguments.
Excuses aside, here's my Powershell invocation of JetBrains DotCover.
$testRunner = "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\MSTest.exe"
$testContainers = "D:\org\branch\namespace\domain\project.tests\bin\Output\Org.Namespace.Domain.Project.Tests.dll","D:\org\branch\namespace\domain\project.tests\bin\output\Org.Namespace.Domain.Project.Tests.dll"
foreach($test in $testContainers)
{
$testAssembly = Get-Item $test
$namespace = $testAssembly.BaseName -replace ".tests", ""
$testName = $testAssembly.Name
$testDirectory = (Split - Path $test - Parent)
$testReport = "C:\temp\$testName.trx" & $coverageTool cover /TargetExecutable = "$testRunner" / Filters = "-:$namespace.Tests;+:class=$namespace*" /TargetArguments = "/testContainer:$test /resultsFile:$testReport" / Output = "C:\temp\$testName.dcvr" / LogFile ="C:\DotCover.log.txt"
}
Supporting DotCover in our build pipeline was almost painless. The only part where I struggled was on the DotCover command line documentation. It took me a good while to realise that TargetArguments is where I specify the command line arguments used by the test-runner. In our case, the actual MSTest command line arguments.
Excuses aside, here's my Powershell invocation of JetBrains DotCover.
At present, we do not use the XML configuration files. But, when Developers start producing their own XML configurations within each visual studio solution, I shall implement that functionality later.
Instrumentation & Test
We automatically exclude the test assembly namespace from the coverage analysis.
Instrumentation & Test
We automatically exclude the test assembly namespace from the coverage analysis.
- We're not interested in how well our tests cover our tests.
- i.e. com.product.domain.project.tests
- Any unintentional coverage of other projects is discarded.
- i.e. com.product.domain.project
- i.e. com.product.domain
$testRunner = "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\MSTest.exe"
$testContainers = "D:\org\branch\namespace\domain\project.tests\bin\Output\Org.Namespace.Domain.Project.Tests.dll","D:\org\branch\namespace\domain\project.tests\bin\output\Org.Namespace.Domain.Project.Tests.dll"
foreach($test in $testContainers)
{
$testAssembly = Get-Item $test
$namespace = $testAssembly.BaseName -replace ".tests", ""
$testName = $testAssembly.Name
$testDirectory = (Split - Path $test - Parent)
$testReport = "C:\temp\$testName.trx" & $coverageTool cover /TargetExecutable = "$testRunner" / Filters = "-:$namespace.Tests;+:class=$namespace*" /TargetArguments = "/testContainer:$test /resultsFile:$testReport" / Output = "C:\temp\$testName.dcvr" / LogFile ="C:\DotCover.log.txt"
}
Report Merging
The next steps merge up all the individual coverage reports generated by the unit test runs. This gives us our test coverage for the domain : com.product.domain.project.
$testReports = $testContainers | % {
$name = Split-Path $_ -Leaf
return ("c:\temp\{0}.dcvr" -f $name)
}
$testReportArgument = [String]::Join(";", $testReports)
& $coverageTool merge /Source="$testReportArgument" /Output="C:\temp\mergedSnapshots.dcvr"
HTML Report
$name = Split-Path $_ -Leaf
return ("c:\temp\{0}.dcvr" -f $name)
}
$testReportArgument = [String]::Join(";", $testReports)
& $coverageTool merge /Source="$testReportArgument" /Output="C:\temp\mergedSnapshots.dcvr"
Report Generation
The unified domain coverage reports can now be transformed into useful reportsHTML Report
Handy for quick review of coverage issues. We archive these reports in the build artefacts for the purposes of providing quick lookups. The reports persist until removed by the TFS retention policies.
& $coverageTool report /Source="C:\temp\mergedSnapshots.dcvr" /Output="C:\temp\mergedReport.html" /ReportType="HTML"
& $coverageTool report /Source="C:\temp\mergedSnapshots.dcvr" /Output="C:\temp\mergedReport.html" /ReportType="HTML"
XML Report
Ideal format for the next stage where I extract the coverage metrics to complete the code quality assessment in the build pipeline.
& $coverageTool report /Source="C:\temp\mergedSnapshots.dcvr" /Output="C:\temp\mergedReport.xml" /ReportType="XML"
& $coverageTool report /Source="C:\temp\mergedSnapshots.dcvr" /Output="C:\temp\mergedReport.xml" /ReportType="XML"
& $coverageTool report /Source="C:\temp\mergedSnapshots.dcvr" /Output="C:\temp\mergedReport.xml" /ReportType="XML"
Summary Extraction
The XML report provides a lot of information, but for the purposes of "Pass or Fail", I just need the combined coverage percentage. If it's falls below our agreed threshold, then the build must fail.
[xml]$coverageAnalysis = Get-Content "C:\temp\$mergedReport.xml"
$blocksCovered = $coverageAnalysis.Root.CoveredStatements;
$totalBlocks = $coverageAnalysis.Root.TotalStatements;
$totalCoverage = $coverageAnalysis.Root.CoveragePercent;
[xml]$coverageAnalysis = Get-Content "C:\temp\$mergedReport.xml"
$blocksCovered = $coverageAnalysis.Root.CoveredStatements;
$totalBlocks = $coverageAnalysis.Root.TotalStatements;
$totalCoverage = $coverageAnalysis.Root.CoveragePercent;
This line $testReport = "C:\temp\$testName.trx" & $coverageTool cover /TargetExecutable = "$testRunner" is showing error while running in windows power shell.
ReplyDeleteError is: Unexpected token '&' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
Please help in this context and explain the significance of that line.