4

I'm using Pester to test a PowerShell script that dot-sources another script. When I try to mock the function that is dot-sourced, Pester refuses to use the mocked version. I'm having the same problem when I try to source the function by using adding it to a .psm1 file and using Import-Module instead of dot-sourcing.

Here's an example that replicates the problem I'm having. All 3 files are in the same folder.

Foo.ps1

Function Invoke-Foo{
    'Cantelope'
}

Bar.ps1

function Invoke-Bar {
    . .\foo.ps1
    Invoke-foo
}

Bar.tests.ps1

$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
. "$here\$sut"
. .\Foo.ps1

Describe "Bar" {
    It "Mocks Foo" {
        Mock Invoke-Foo {'Banana'}
        Invoke-Bar | should be 'Banana'
    }
}

After mocking Invoke-Foo, the result should be 'Banana', but the result is:

Describing Bar
 [-] Mocks Foo 36ms
   Expected string length 6 but was 9. Strings differ at index 0.
   Expected: {Banana}
   But was:  {Cantelope}
   -----------^
   9:         Invoke-Bar | should be 'Banana'
   at <ScriptBlock>, C:\Users\geinosky\Desktop\PingTest\Bar.tests.ps1: line      9

How can I get Pester to correctly work with the dot-sourced function?

jgeinosky
  • 41
  • 2

1 Answers1

5

Invoke-Bar explicitly dot-sources Invoke-Foo from a file and then invokes it. The dot-sourced function hides other defined Invoke-Foo, including mocked.

If we remove . .\foo.ps1 from Invoke-Bar then the Pester mock works, we get "Banana".

If then we remove the mock then all works, i.e. all commands are found, but we get "Cantelope".

In other words, if you want Invoke-Foo to be mockable then do not dot-source it in Invoke-Bar. Invoke-Bar should assume Invoke-Foo is pre-defined (the original or mocked) and just use it.

Roman Kuzmin
  • 40,627
  • 11
  • 95
  • 117