I have a function that uses Invoke-RestMethod
to send data to an API. The API accepts data in different ways (Body, Header, QueryString) so the function takes in the data plus 2 parameters that determine how the data will be sent. Using a switch
statement the data is added to the corresponding HashTable
and then passed as a parameter to Invoke-RestMethod
. Function code is below.
Function
function Invoke-GetRequest {
param(
[Parameter(Mandatory)]
[String] $Url,
[Parameter(Mandatory)]
[String] $TechnicianKey,
[ValidateNotNullOrEmpty()]
[String] $InputData,
[ValidateSet("Body","Header","QueryString")]
[String] $SendTechnicianKeyIn="Header",
[ValidateSet("Body","QueryString")]
[String] $SendInputDataIn="Body"
)
$header = @{}
$data = @{}
$queryString = @{}
switch($SendTechnicianKeyIn) {
"Body" {$data.Add('TECHNICIAN_KEY',$TechnicianKey)}
"Header" {$header.Add('TECHNICIAN_KEY', $TechnicianKey)}
"QueryString" {$queryString.Add('TECHNICIAN_KEY', $TechnicianKey)}
}
switch($SendInputDataIn) {
"Body" {$data.Add('input_data', $InputData)}
"QueryString" {$queryString.Add('input_data', $InputData)}
}
if($queryString.Count -gt 0) {
$uri = Format-HttpQueryString -Uri $Url -QueryParameter $queryString
}
else {
$uri = $Url
}
$response = Invoke-RestMethod -Uri $uri -Method Get -Headers $header -Body $data -ErrorAction Stop
$response
}
I am writing unit tests using Pester so have mocked Invoke-RestMethod
and I need to verify that the data is being added to the correct HashTable
and is therefore Invoke-RestMethod
is called with the correct parameters.
I have not found a way to directly test the HashTable
s so the only way I can think to do this is to use a ParameterFilter
on the Mock
so that it is only called if the filter matches but if I do that and the filter doesn't match then a call goes out to the real Invoke-RestMethod
which obviously is not wanted in a unit test. Below is an example of the Pester
test.
Pester Test
Context 'Valid Calls' {
BeforeAll {
$splat = @{
Url = 'https://www.test.com/api/'
TechnicianKey = '00000000-0000-0000-0000-000000000000'
InputData = '{"list_info":{"row_count":"10"}}'
}
}
Describe 'TechnicianKey Header, InputData Body Default' {
BeforeAll {
Mock Invoke-RestMethod -ParameterFilter { $uri -eq $splat.Url -and $header.TECHNICIAN_KEY -eq $splat.TechnicianKey -and $data.input_data -eq $splat.InputData }} {}
}
It 'Should invoke Invoke-RestMethod once' {
Invoke-GetRequest @splat
Should -Invoke -CommandName Invoke-RestMethod -Times 1 -Exactly
}
}
}
Posting my final solution for future reference. I used the
ParameterFilter
with the different values for theUri
,Headers
andBody
so that an error would be thrown if theMock
never fired. This still doesn't fully solve the problem though because say I was refactoring/updating this code in the future and I make a change so that the filter no longer matches, then this is going to make a real call toInvoke-RestMethod
.