Pester includes keywords that hold code that will execute before or after either each test or all tests. The following keywords are available:
- BeforeAll: Executed once, before all other content
- AfterAll: Executed once, after all other content
- BeforeEach: Executed immediately before each individual test
- AfterEach: Executed immediately after each individual test
Each of the keywords should be followed by a script block.
When using Before or After it is important to be aware of the order in which a section is executed. In the following list, Loose code refers to anything that is not part of a Before, After, or It:
- DescribeBeforeAll
- DescribeLoose code
- ContextBeforeAll
- ContextLoose code
- DescribeBeforeEach
- ContextBeforeEach
- ContextLoose code
- It
- ContextAfterEach
- DescribeAfterEach
- ContextAfterAll
- DescribeAfterAll
It is important to note that if Mocks are created under a describe block, they are categorized as Loose code in the context of this list. A command called in DescribeBeforeAll will not have access to mocks that are only created further down the list.
When using Before or After, consider enclosing Mocks in BeforeAll or It (if Mocks are specific to a single test) to ensure Mocks are always available where they might be used.
The following function is used to demonstrate how Before and After might be used. The function deletes files in a specified path where the last access time was defined at least a number of days ago:
function Remove-StaleFile { param ( [Parameter(Mandatory = $true)] [String]$Path, [String]$Filter = '*.*', [Int32]$MaximumAge = 90 ) Get-ChildItem $Path -Filter $Filter | Where-Object LastWriteTime -lt (Get-Date).AddDays(-$MaximumAge) | Remove-Item }
To test the function, a number of test cases might be constructed. BeforeAll, BeforeEach, and AfterAll might be used to ensure everything is ready for an individual test. Each of the following elements is contained within a single Describe block.
BeforeAll is used to create a temporary working path:
BeforeAll { $extensions = '.txt', '.log', '.doc' $Path = 'C:TempStaleFiles' $null = New-Item $Path -ItemType Directory Push-Location $Path }
AfterAll is used to clean up:
AfterAll { Pop-Location Remove-Item C:TempStaleFiles -Recurse -Force }
And BeforeEach is used to create a known set of files before each test executes:
BeforeEach { foreach ($extension in $extensions) { $item = New-Item "stale$extension" -ItemType File -Force $item.LastWriteTime = (Get-Date).AddDays(-92) } foreach ($extension in $extensions) { $item = New-Item "new$extension" -ItemType File -Force $item.LastWriteTime = (Get-Date).AddDays(-88) } }
The tests themselves are simplified, needing only the code required to execute and test the impact of the function:
It 'Removes all files older than 90 days' { Remove-StaleFile $Path Test-Path "stale.*" | Should -Be $false Get-ChildItem "new.*" | Should -Not -BeNullOrEmpty } $testCases = $extensions | ForEach-Object { @{ Extension = $_ } } It 'Removes all <Extension> files older than 90 days' -TestCases $testCases { param ( $Extension ) Remove-StaleFile $Path -Filter "*$Extension" Test-Path "stale$Extension" | Should -Be $false Get-ChildItem "stale.*" | Should -Not -BeNullOrEmpty Get-ChildItem "new.*" | Should -Not -BeNullOrEmpty }