Author Posts

July 27, 2018 at 12:35 pm

testmodule.psm1

function Invoke-Public ($param)
{
    Invoke-Private -param $param
}
function Invoke-Private ($param)
{
    try
    {
        $Res = Resolve-DnsName -Name $param -DnsOnly -ErrorAction Stop
        return $Res
    }
    catch
    {
        return $_
    }
}
Export-ModuleMember -Function Invoke-Public

testmodule.Tests.ps1

Import-Module testmodule
InModuleScope testmodule {
    $FQDN = "fqdn.domain.com"
    $Netbios = "hostname"
    Mock Resolve-DnsName {
        if ($Name -eq $FQDN)
        {
            return "true Name $Name. FQDN - $FQDN"
        }
        elseif ($Name -eq $Netbios)
        {
            return "false Name $Name. Netbios - $Netbios"
        }
        else
        {
            return "3rd Name $Name. FQDN - $FQDN. Netbios - $Netbios"
        }
    }
    Describe 'Private function test' {
        It 'Passes Invoke-Private with ' -TestCases @(
            @{Value = $FQDN; Expected = "true Name $FQDN. FQDN - $FQDN"}
            @{Value = $Netbios; Expected = "false Name $Netbios. Netbios - $Netbios"}
        ) {
            param ($Value, $Expected)
            Invoke-Private -param $Value | Should -Be $Expected
        }
    }
}
Describe 'Public function test' {
    $FQDN = "fqdn.domain.com"
    It 'Passes Invoke-Public' {
        Invoke-Public -param $FQDN | Should -Be "true Name $FQDN. FQDN - $FQDN"
    }
}

tests result:

Executing Test
Executing all tests in '..\test'

Executing script C:\Temp\test\testmodule.Tests.ps1

Describing Private function test
[+] Passes Invoke-Private with 'fqdn.domain.com' 4.04s
[+] Passes Invoke-Private with 'hostname' 284ms

Describing Public function test
[-] Passes Invoke-Public 1.21s
Expected strings to be the same, but they were different.
Expected length: 49
Actual length: 45
Strings differ at index 0.
Expected: 'true Name fqdn.domain.com. FQDN – fqdn.domain.com'
But was: '3rd Name fqdn.domain.com. FQDN – . Netbios – '
———–^
32: Invoke-Public -param $FQDN | Should -Be "true Name $FQDN. FQDN – $FQDN"
at , C:\Temp\test\testmodule.Tests.ps1: line 32
Tests completed in 5.54s
Tests Passed: 2, Failed: 1, Skipped: 0, Pending: 0, Inconclusive: 0

Why the $FQDN and $Netbios variables are not available for mocked Resolve-DnsName function? How should I make them available, or what would be the recommended way to test in this scenario?

July 27, 2018 at 2:24 pm

(Apologies for the spurious incorrect forum post you may have received; that was a bot that didn't catch the right keywords)

Gimme a sec to try this on my own!

July 27, 2018 at 2:31 pm

Yeah, so the problem is just that you've passed out of scope for the mock. Mocks are really designed to mock a function that is being run in a test; they're not designed to mock functions that exist elsewhere in a module. The module's "local" definition of the function or command "wins," because it's more local. Because you're calling a function, which is calling a function, the mock gets "lost," if you will.

Struggling to explain, but maybe think of it this way: you've seen that you can go "one level" deep with Invoke-Private. What you can't do is go "deeper." Does that make sense?

July 31, 2018 at 6:37 am

I am not sure I understand, to me it seems that the mock is working, it returns the mocked string just with empty variables. My observation is that the variables defined InModuleScope are available when calling mocked function in that same scope, but they are not available when calling in public scope (from within a public function).

Now I'm on my phone and can't double check, but I think I was getting the expected result if I just used strings in if checks in mocked function, instead of using $fqdn and $netbios variables.

August 1, 2018 at 5:26 pm

Your observation is correct. The public function will not have access to those variables because it it outside the scope of where the mock is defined. If you move the public function test into that scope(InModuleScope testmodule) then the mocked outputs will be available to your public function.