A function that writes files
Every function so far has returned a value. Testing those is easy: call it, look at what came back. This page adds a function whose entire purpose is a side effect — it writes a file and returns nothing useful.
Export-PlanetReport
function Export-PlanetReport {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string] $Path,
[string] $Name = '*'
)
$planets = @(Get-Planet -Name $Name)
if ($planets.Count -eq 0) {
throw "No planets matched '$Name'."
}
$report = foreach ($planet in $planets) {
'{0,-8} {1} AU' -f $planet.Name, (ConvertTo-AstronomicalUnit -Kilometre $planet.DistanceFromSunKm)
}
Set-Content -Path $Path -Value $report
}
It leans on almost everything built so far: Get-Planet for the data, the private ConvertTo-AstronomicalUnit for the conversion, and the module loader to wire them together. It goes in Public/, so it is exported automatically.
Note @(Get-Planet -Name $Name). Without the array subexpression, a single match returns a bare object with no .Count, and the emptiness check would misbehave. This is a normal PowerShell trap rather than a Pester one, but it is the kind of thing a test catches and a quick manual check does not.
Try it:
Import-Module ./Planetarium/Planetarium.psd1 -Force
Export-PlanetReport -Path ./report.txt
Get-Content ./report.txt
Mercury 0.387 AU
Venus 0.723 AU
Earth 1 AU
Mars 1.524 AU
Jupiter 5.204 AU
Saturn 9.582 AU
Uranus 19.201 AU
Neptune 30.047 AU
The problem with testing this
You have just created a file in your source folder. Delete it:
Remove-Item ./report.txt
Now think about what a test for this function has to do. It needs a path to write to, and afterwards that file should not still be there. Doing this by hand goes wrong quickly:
- Writing into the repo leaves junk in
git status, and one forgotten cleanup means a test that passes only because a previous run left the file behind. - Writing to a fixed temp path breaks the moment two tests use the same name, and breaks harder when two Pester runs happen at once.
- Cleaning up in
AfterEachis correct until a test fails midway and the cleanup never runs — so the failure poisons the next run too.
Every one of these produces the same nasty class of bug: tests whose result depends on what previous runs left lying around. They pass on your machine, fail in CI, and pass again after you delete something by hand.
Set-Content?You could — Mock Set-Content and Should-Invoke would tell you the function tried to write. But it would not tell you the file has eight lines, or that Earth's line reads Earth 1 AU. You would be asserting that your code called a command, not that it produced a correct report.
Mock the filesystem when the write itself is the behaviour. When the content matters, write real files somewhere disposable — which is exactly what the next page is about.
Before you move on
0/4Next: the disposable filesystem Pester gives you for free.