Mocking with Pester

Hi,

I am trying to write a unit Pester test and not sure why I cannot get this to work. I am trying to verify that each code path works correctly. My function is below along with my Pester test. Please help! My function is calling an exposed Web Endpoint. I have tried different ways to mock out the responses but the common error I am getting is "You cannot call a method on a null-valued expression’ which is pointing to the $obj variable. I understand the error but I thought it would be bypassed since I am mocking the New-Object cmdlet.

Function

function Test-Endpoint {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    ValueFromPipeline=$true,
                    HelpMessage="Write anything to echo")]
        [string]$Message
    )
    Begin {
        $uris = 'x','y','z'
        Write-Verbose "URI's to test: $uris"
    }
    Process {
        Write-Verbose "Beginning Process block"
        foreach ($uri in $uris) {
            Try{
                $uri = "http://$uri/Something.svc/echo/$message"
                $request = Invoke-WebRequest   -Uri "$uri" `
                                    -Method 'Get' `
                                    -ContentType 'application/json' `
                                    -UseBasicParsing `
                                    -ErrorAction Stop
            } Catch {
                Write-Warning "$uri failed to return echo message"
                Write-Warning "$_.Exception.Message"
            }
            if($?) {
                Write-Verbose "Test $uri echo complete"
                $props = @{ 'URI' = $uri;
                            'StatusCode' = $request.StatusCode;
                            'Status' = $request.StatusDescription;
                            'Content' = $request.Content}
                $obj = New-object -TypeName PSObject -Property $props
                $obj.PSObject.TypeNames.Insert(0,'xyz.SystemInfo')
                Write-Output $obj
            }
        }
    }
    End {}
}

Pester Unit Test

Import-Module SomeModule

Describe "Test-Endpoint" {
    InModuleScope SomeModule {
        it 'attempts to return echo message if Invoke is successful' {
            mock -CommandName Invoke-WebRequest -MockWith {
                $request = @{'URI' = 'someURI';
                            'Content' = 'someContent';
                            'Status' = 'someStatus';
                            'StatusCode' = 'someStatusCode'
                            }
                return $request
            }
            mock -CommandName New-Object -MockWith {
                $obj = $result
                return $($obj.typeNames.Insert(0,'xyz.SystemInfo'))
            }
            Test-Endpoint -Message "SomeMessage"
            Assert-MockCalled -CommandName 'Invoke-WebRequest' -Times 1 -Scope It
            Assert-MockCalled -CommandName 'New-Object' -Times 1 -Scope It
        }
        it 'returns error message if invoke to endpoint fails' {
            mock -CommandName Invoke-WebRequest -MockWith {
                    return $Error
            }
            mock -CommandName 'New-Object' -MockWith { 
                return $null
            }
            Test-CorpSysBillingSummaryEcho -Message "someMessage"
            Assert-MockCalled Invoke-WebRequest -Times 1 -Scope It
            Assert-MockCalled New-Object -Times 0 -Scope It
        }   
    }    
}

You are mocking New-Object with the exact same code that’s actually running. I’d remove that mock and test that the function returns the expected object.

Hi,

3rd editing my response here. Sorry. What do you think about this? Is there a better way to do this? Any advice? I still want to create another Context block for when the codepath goes to Error. Not sure how to do that yet.

Import-Module SomeModule

Describe "Test-Endpoint" {
    InModuleScope SomeModule {
        Context 'Verifying success code path of echo method and expected fields are present & not null' {
            it 'attempts to invoke web api code path' {
                mock -CommandName Invoke-WebRequest -MockWith {
                    $request = @{'URI' = 'someURI';
                                'Content' = 'someContent';
                                'Status' = 'someStatus';
                                'StatusCode' = 'someStatusCode'
                                }
                    return $request
                }
                $global:result = Test-Endpoint -Message "SomeMessage"
                Assert-MockCalled -CommandName 'Invoke-WebRequest' -Times 1 -Scope It
            }
            it 'URI field exists and not null' {
                $result.URI.ToString() | Should Not Be $null
            }
            it 'Content field exists and not null' {
                $result.Content.ToString() | Should Not Be $null
            }
            it 'Status field exists and not null' {
                $result.Status.ToString() | Should Not Be $null
            }
            it 'StatusCode field exists and not null' {
                $result.StatusCode.ToString() | Should Not Be $null
            }
            it '4 NoteProperties exist' {
                ($result | Get-Member -MemberType NoteProperty).length | Should Be 4
            }
        }
    }
}