Skip to content

Instantly share code, notes, and snippets.

@alx9r
Last active August 3, 2017 16:36
Show Gist options
  • Save alx9r/56bbc9077b39e5693b08821183d89c21 to your computer and use it in GitHub Desktop.
Save alx9r/56bbc9077b39e5693b08821183d89c21 to your computer and use it in GitHub Desktop.
Tests summarizing scope-related differences for mocks between Pester 3 and 4
$guid = [guid]::NewGuid().Guid
$guidFrag = $guid.Split('-')[0]
$h = @{}
$h.MyInvocation = $MyInvocation
$directlyInvoked = -not [bool]$h.MyInvocation.Line
$h.TempTestScript = "$([System.IO.Path]::GetTempPath())\$guidFrag.Tests.ps1"
function Set-PesterVersion
{
[CmdletBinding()]
param
(
[ValidateSet('3','4')]
[string]$Version
)
process
{
$versionTest = @{
'3' = { $_.Version -lt '4.0.0' }
'4' = { $_.Version -ge '4.0.0' }
}.$Version
Remove-Module Pester -ErrorAction SilentlyContinue
$module = Get-Module -ListAvailable Pester |
? $versionTest |
Select -First 1
if ( -not $module )
{
throw "Pester module version $Version not found."
}
$module | Import-Module -ErrorAction SilentlyContinue
$module = Get-Module Pester |
? $versionTest
if ( -not $module )
{
throw "Failed to load Pester module version $Version."
}
Write-Output "Pester $Version"
}
}
$setup = {
function Set-TestModules
{
# import one dynamic module from another'
# create module A'
$h.ModuleA = New-Module -Name "ModuleA-$guid" -ScriptBlock (
[scriptblock]::Create(@"
function A1-$guid { 'real result of A1' }
function A2-$guid { "A2 calls A1: `$(A1-$guid)" }
"@
))
$h.ModuleA | Import-Module -Force -WarningAction SilentlyContinue
# create module B'
$h.ModuleB = New-Module -Name "ModuleB-$guid" -ScriptBlock (
[scriptblock]::Create(@"
Get-Module ModuleA-$guid | Import-Module -WarningAction SilentlyContinue
function B-$guid { "B calls A1: `$(A1-$guid)" }
"@
))
$h.ModuleB | Import-Module -Force -WarningAction SilentlyContinue
#create module C
$h.ModuleC = New-Module -Name "ModuleC-$guid" -ScriptBlock (
[scriptblock]::Create("function C-$guid { `"C calls A1: `$(A1-$guid)`" }" )
)
$h.ModuleC | Import-Module -Force -WarningAction SilentlyContinue
}
}
function Invoke-TestWithPester
{
param
(
[scriptblock]
$ScriptBlock
)
{ $directlyInvoked = $false }.ToString() +
$ScriptBlock.ToString() +
$setup.ToString() |
Set-Content $h.TempTestScript
Invoke-Pester $h.TempTestScript
}
& $setup
Set-TestModules
Describe 'test the test modules' {
It 'command in inner module works' {
$r = & "A1-$guid"
$r | Should be 'real result of A1'
}
It 'command in outer module calls inner module' {
$r = & "B-$guid"
$r | Should be 'B Calls A1: real result of A1'
}
It 'command in outer module calls inner module even though inner module is not imported' {
$r = & "C-$guid"
$r | Should be 'C Calls A1: real result of A1'
}
}
foreach ( $values in @(
@('directly (like F5 does)',{ & $test }),
@('with Invoke-Pester',{ Invoke-TestWithPester $test })
))
{
$methodName,$invoker = $values
Write-Output "#### Invoking Test $methodName ####"
Set-PesterVersion 3
$test = {
Describe "Pester 3: effect of InModuleScope on whether a mock or real command is invoked" {
Context 'indirectly invoke mocked command from another module without InModuleScope' {
Mock "A1-$guid" { 'mocked result of A1' }
It 'returns result from real function' {
$r = & "B-$guid"
$r | Should be 'B calls A1: real result of A1'
}
}
Context 'indirectly invoke mocked command from mocked command''s module without InModuleScope' {
Mock "A1-$guid" { 'mocked result of A1' }
It 'returns result from real function' {
$r = & "A2-$guid"
$r | Should be 'A2 calls A1: real result of A1'
}
}
}
}
& $invoker
Set-PesterVersion 4
$test = {
Describe 'Pester 4: effect of InModuleScope on whether a mock or real command is invoked' {
Context 'indirectly invoke mocked command from another module without InModuleScope' {
Mock "A1-$guid" { 'mocked result of A1' }
if ( $directlyInvoked )
{
It 'returns result from mock (when script invoked directly)' {
$r = & "B-$guid"
$r | Should be 'B calls A1: mocked result of A1'
}
}
else
{
It 'returns result from real function (when script invoked by Pester)' {
$r = & "B-$guid"
$r | Should be 'B calls A1: real result of A1'
}
}
}
Context 'indirectly invoke mocked command from mocked command''s module without InModuleScope' {
Mock "A1-$guid" { 'mocked result of A1' }
if ( $directlyInvoked )
{
It 'returns result from mock (when scripted invoked directly)' {
$r = & "A2-$guid"
$r | Should be 'A2 calls A1: mocked result of A1'
}
}
else
{
It 'returns result from real function (when scripted invoked by Pester)' {
$r = & "A2-$guid"
$r | Should be 'A2 calls A1: real result of A1'
}
}
}
}
}
& $invoker
Set-PesterVersion 3
$test = {
Describe 'Pester 3: effect of not importing module inside module that invokes mocked command' {
It 'set TestDrive file contents' {
$guid | Set-Content 'TestDrive:\guid.txt'
}
if ( $directlyInvoked )
{
Context 'indirectly invoke mocked command from another non-importing module without InModuleScope' {
Mock "A1-$guid" { 'mocked result of A1' }
It 'returns result from real function (when script invoked directly)' {
$r = & "C-$guid"
$r | Should be 'C calls A1: mocked result of A1'
}
}
}
else
{
Context 'indirectly invoke mocked command from another non-importing module without InModuleScope' {
Mock "A1-$guid" { 'mocked result of A1' }
It 'throws CommandNotFoundException for mocked command (when script invoked by Pester)' {
try
{
& "C-$guid"
}
catch
{
$threw = $true
$_.FullyQualifiedErrorId | Should be CommandNotFoundException
$_ | Should match "The term 'A1"
}
$threw | Should be $true
}
}
InModuleScope "ModuleA-$guid" {
$guid = Get-Content 'TestDrive:\guid.txt'
Context 'indirectly invoke mocked command from another non-importing module InModuleScope of the mocked command''s module' {
Mock "A1-$guid" { 'mocked result of A1' }
It 'throws CommandNotFoundException for mocked command (when script invoked by Pester)' {
try
{
& "C-$guid"
}
catch
{
$threw = $true
$_.FullyQualifiedErrorId | Should be CommandNotFoundException
$_ | Should match "The term 'A1"
}
$threw | Should be $true
}
}
}
InModuleScope "ModuleC-$guid" {
$guid = Get-Content 'TestDrive:\guid.txt'
Context 'indirectly invoke mocked command from another non-importing module InModuleScope of non-importing module' {
try
{
Mock "A1-$guid" { 'mocked result of A1' }
}
catch [System.Management.Automation.CommandNotFoundException]
{
$threw = $true
$exception = $_
}
It 'throws CommandNotFoundException when mocking command (when script invoked by Pester)' {
$threw | Should be $true
}
}
}
}
}
}
& $invoker
Set-PesterVersion 4
$test = {
Describe 'Pester 4: effect of not importing module inside module that invokes mocked command' {
It 'set TestDrive file contents' {
$guid | Set-Content 'TestDrive:\guid.txt'
}
Context 'indirectly invoke mocked command from another non-importing module without InModuleScope' {
Mock "A1-$guid" { 'mocked result of A1' }
if ( $directlyInvoked )
{
It 'returns result from mock (when script invoked directly)' {
$r = & "C-$guid"
$r | Should be 'C calls A1: mocked result of A1'
}
}
else
{
It 'returns result from real function (when script invoked by Pester)' {
$r = & "C-$guid"
$r | Should be 'C calls A1: real result of A1'
}
}
}
if ( -not $directlyInvoked )
{
InModuleScope "ModuleA-$guid" {
$guid = Get-Content 'TestDrive:\guid.txt'
Context 'indirectly invoke mocked command from another non-importing module InModuleScope of the mocked command''s module' {
Mock "A1-$guid" { 'mocked result of A1' }
It 'returns result from real function (when script invoked directly)' {
$r = & "C-$guid"
$r | Should be 'C calls A1: real result of A1'
}
}
}
}
}
}
& $invoker
}
Remove-Variable 'guid','h'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment