powershellclassmockingpester

Pester Mock a command within a PowerShell class function


I've found a lot of questions about mocking a function (method) within a PowerShell class. The question I have (and can't find an answer for) is, is it possible to mock a cmdlet call that is contained within a PowerShell class?

To be clear - this is about testing the function/method in the class, not mocking the function/method from the class for which there are a number of options available.

Example: PowerShell Class - test.psm1

class MyClass {
    [string]$filecontent

    MyClass() {}

    [void] GetFileContent([string]$filepath) {
        $this.filecontent = Get-Content -Path $filepath -raw
    }
}

Pester file:

using module .\test.psm1

Describe "MyClass" {
    BeforeAll {
        $objClass = [MyClass]::new()
        Mock Get-Content { return "this-is-a-test" }
        $objClass.GetFileContent("c:\temp\myfile.txt")
    }

    It "Should update class variable" {
         $objClass.filecontent | Should -be "test-is-a-test"
    }

    AfterAll {
        Remove-Variable objClass
    }
}

I had expected (or rather hoped) to mock the cmdlet Get-Content within the class function/method GetFileContent, but Get-Content is not mocked - and it tries to call the file which may not exist in testing. Any ideas of how to mock these cmdlets?

Many thanks

Martin


Solution

  • The key to make this work is to use the -ModuleName Parameter in your Mock statement, this is so the cmdlet gets overridden in the Module's scope.

    Optional string specifying the name of the module where this command is to be mocked. This should be a module that calls the mocked command; it doesn't necessarily have to be the same module which originally implemented the command.

    The argument for ModuleName in this case would be test, this is determined by your psm1 file name.

    In summary:

    using module .\test.psm1
    
    Describe 'MyClass' {
        BeforeAll {
            Mock Get-Content -ModuleName test { return 'this-is-a-test' }
            $objClass = [MyClass]::new()
            $objClass.GetFileContent('c:\temp\myfile.txt')
        }
    
        ....
        ....
    }
    

    Alternatively, hint provided by zett42, you can use InModuleScope wrapping Describe:

    using module .\test.psm1
    
    InModuleScope 'test' {
        Describe 'MyClass' {
            BeforeAll {
                Mock Get-Content { return 'this-is-a-test' }
                $objClass = [MyClass]::new()
                $objClass.GetFileContent('c:\temp\myfile.txt')
            }
    
            ....
            ....
        }
    }