Integrating PsUnit and MSBuild
The last month I have been digging into, adding new and refactoring the Powershell scripts we use in RemoteX Applications. We primarily use PowerShell to configure and deploy our product.
<![CDATA[
<PropertyGroup>
<CoreTestDependsOn>$(CoreTestDependsOn);RunPsUnit</CoreTestDependsOn>
<RunPsUnitDependsOn>CoreRunPsUnit</RunPsUnitDependsOn>
</PropertyGroup>
<Target Name="RunPsUnit" DependsOnTargets="$(RunPsUnitDependsOn)"/>
<Target Name="CoreRunPsUnit" Condition=" '$(RunTest)'!='false' ">
<Exec Command="$(PowerShell) -Command "&{ .\runpsunit.ps1 -PsUnitTestFile %(PsUnitTest.FullPath) }""/>
</Target>
]]>
Using this batch target, all that needs to be done is to add PsUnitTest items to the build script. Just like the way we set up TestContainer items for use with MSTest:
<![CDATA[
<ItemGroup>
<PsUnitTest Include="$(SolutionRoot)\Scripts\Tests\*.Test.ps1"/>
<PsUnitTest Include="$(SolutionRoot)\References\PsUnit\*.Test.ps1"/>
</ItemGroup>
]]>
So far so good, but when tests are failing, the build is successful. This is because the Exec task only reports a build error when the executed command returns an exit code other than zero (0×0). So I started looking into the test runner of PsUnit (PsUnit.Run.ps1) and discovered that it didn’t send any output nor produced some other exit code than 0×0. The only output PsUnit will send you is some nice colorful information written to the PowerShell host.
<![CDATA[
$TestResults
]]>
This makes PsUnit.Run.ps1 send the test results along the pipeline.
<![CDATA[
$results = Invoke-Expression "$psUnitRun -PsUnitTestFile $PsUnitTestFile"
$results | % {
if( $_.Result -eq "FAIL" ) {
throw "Test run failed: $($_.Test) - $($_.Reason)"
}
}
]]>
This makes the Exec task report a build error if we find any failing test in the test result from PsUnit – and last but not least – the name of the failing test and the reason ends up nicely in the MSBuild log file.