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 HashTables 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
ParameterFilterwith the different values for theUri,HeadersandBodyso that an error would be thrown if theMocknever 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.