Skip to content

Migrating from Pester 3 to Pester 4

Wojciech Sciesinski edited this page Jun 4, 2018 · 15 revisions

Migration from Pester 3 to 4 typically involves minor changes to test code. Sometimes the migration requires no changes at all. This guide is meant to help you understand and make the necessary changes to your existing test code to accommodate Pester 4.

Update to New Names

We recommend performing string replacement on tests written for Pester 3 and earlier as follows:

  1. replace all occurrences of any Contain assertion with FileContentMatch.
  2. rename all occurrences of Assert-VerifiableMocks to Assert-VerifiableMock

You can use this simple script that can migrate test files in UTF8 and ASCII encoding.

⚠️ Please verify manually results generated by the script - it can generate false positive replaces!

param ($Path = '.')

# version 2017-12-13

$testFiles = $(Get-ChildItem -Path $Path -Recurse *.Tests.ps1).FullName

foreach ($file in $testFiles)
{
    "Migrating '$file'"
    $encoding = Get-FileEncoding -Path $file
    $content = Get-Content -Path $file -Encoding $encoding
    $content = $content -replace 'Should\s+\-?Contain', 'Should -FileContentMatch'
    $content = $content -replace 'Should\s+\-?Not\s*-?Contain', 'Should -Not -FileContentMatch'
    $content = $content -replace 'Assert-VerifiableMocks', 'Assert-VerifiableMock'
    $content | Set-Content -Path $file -Encoding $encoding
}

function Get-FileEncoding {
    # source https://gist.github.com/jpoehls/2406504
    # simplified.

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
        [string]$Path
    )

    [byte[]]$byte = get-content -Encoding byte -ReadCount 4 -TotalCount 4 -Path $Path

    if ( $byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf )
    { Write-Output 'UTF8' }

    else
    { Write-Output 'ASCII' }
}

## Update to the new assertions syntax

In Pester 4.0 the new assertion syntax was introduced. \
Now assertions can be provided as parameters to Should, that allows richer assertion vocabulary.

### Old syntax

```powershell

    It 'Check something' {
        10 | Should Be 10
    }

New syntax

    It 'Check something' {
        10 | Should Be 10
    }

For most cases tests can be updated using the function provided below.

⚠️ Please verify manually results generated by the script specially if your scripts are not UTF-8 or ASCII encoded!

function Update-PesterTest {
<#
    .SYNOPSIS
    The function intended to update Pester tests notation from version 3.x to 4.x.

    .DESCRIPTION
    Notation for the Should assertion changed between Pester version 3.x and 4.x.
    The function helps to update existing Pester 3.x tests to the new notation.

    Please be aware that if your original Pester test files are encoded differently than UTF-8
    than the final files encoding will be Unicode (UTF-7) / ASCSI.

    .PARAMETER Path
    Path to the file that contain Pester tests to update.

    .PARAMETER Destination
    Path to the file for which updated tests will be saved.

    If the Destination parameter is ommitted tests will be updated in place.
    The content of an original file will be replaced.

    .EXAMPLE

    Update-PesterTest -Path .\Pester3-Tests .\Pester4-Tests

    .NOTES
    Original author
    Chris Dent, @indented-automation

    Updates
    Wojciech Sciesinski, @it-praktyk

    LICENSE
    Copyright 2017 Chris Dent

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    .LINK
    https://github.com/pester/Pester/issues/892
    https://gist.github.com/indented-automation/aeb14825e39dd8849beee44f681fbab3
    https://gist.github.com/jpoehls/2406504
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [Alias('FullName')]
        [System.IO.FileInfo]$Path,
        [Parameter(Mandatory=$false)]
        [String]$Destination
    )

    begin {
        $shouldParams = [String[]](Get-Command Should).Parameters.Keys
    }

    process {
        $Path = $pscmdlet.GetUnresolvedProviderPathFromPSPath($Path)

        $encoding = Get-FileEncoding -Path $Path

        [String]$MessageText = "The file {0} will be {1} encoded." -f $Path, $encoding

        Write-Verbose -Message $MessageText

        $errors = $tokens = @()
        $ast = [System.Management.Automation.Language.Parser]::ParseFile(
            $Path,
            [Ref]$tokens,
            [Ref]$errors
        )

        $script = Get-Content $Path -Raw -Encoding $encoding
        $ast.FindAll(
            {
                param ( $ast )

                $ast -is [System.Management.Automation.Language.CommandAst] -and
                $ast.GetCommandName() -eq 'Should'
            },
            $true
        ) |
            ForEach-Object {
                $_.CommandElements | Where-Object {
                    $_.StringConstantType -eq 'BareWord' -and
                    $_.Value -in $shouldParams -or
                    $_.Value -eq 'Contain'
                }
            } |
            Sort-Object { $_.Extent.StartOffset } -Descending |
            ForEach-Object {
                if ($_.Value -eq 'Contain') {
                    $script = $script.Remove($_.Extent.StartOffset, 7).Insert($_.Extent.StartOffset, '-FileContentMatch')
                } else {
                    $script = $script.Insert($_.Extent.Startoffset, '-')
                }
            }

        if ( [String]::IsNullOrEmpty($Destination)) { $Destination = $Path }

        Set-Content -Path $Destination -Value $script -NoNewline -Encoding $encoding
    }

}

function Get-FileEncoding {
    # source https://gist.github.com/jpoehls/2406504
    # simplified.

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
        [string]$Path
    )

    [byte[]]$byte = get-content -Encoding byte -ReadCount 4 -TotalCount 4 -Path $Path

    if ( $byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf )
    { Write-Output 'UTF8' }

    else
    { Write-Output 'ASCII' }
}

Mock-Related Changes

We are not 100% sure what implications changing from functions to aliases had on mocking. There are no immediate changes that you need to do, but here are two articles that should help you start figuring out issues if you have any:

Array-Related Changes

The Should command now performs array assertions. For the most part this change is transparent to existing tests. There are some edge cases, however, where a test involving an array passes in Pester 3 but fails in Pester 4. This article contains such an example.

Clone this wiki locally