简体   繁体   English

PowerShell Pester Mock Rest API 调用

[英]PowerShell Pester Mock Rest API Calls

Is there any simple approach on how to mock a Rest API Calls in Pester .有没有关于如何在 Pester 中模拟Rest API 调用的简单方法。

Here is my code, I just need to mock those Rest API Calls in Pester and test them, could someone help me here.这是我的代码,我只需要在 Pester 中模拟那些Rest API 调用并测试它们,有人可以在这里帮助我。

Describe 'Test worldclockapi.com' {
    BeforeAll {
        $response = Invoke-WebRequest -Method 'GET' -Uri 'http://worldclockapi.com/api/json/utc/now'
        $responseContent = $response.Content | ConvertFrom-Json
        Write-Output $responseContent
    }

    It 'It should respond with 200' {
        $response.StatusCode | Should -Be 200
    }
    
    It 'It should have a null service response' {
        $responseContent.serviceResponse | Should -BeNullOrEmpty
    } 
    
    It 'It should be the right day of the week' {
        $dayOfWeek = (Get-Date).DayOfWeek
        $responseContent.dayOfTheWeek | Should -Be $dayOfWeek
    }
    
    It 'It should be the right year' {
        $year = Get-Date -Format 'yyyy'
        $responseContent.currentDateTime | Should -BeLike "*$year*"
    }
    
    It 'It should be the right month' {
        $month = Get-Date -Format 'MM'
        $responseContent.currentDateTime | Should -BeLike "*$month*"
    }
    
    # These two tests assume you are running this outside daylight savings (during the winter) .. hacky but good way to showcase the syntax ;)
    It 'It should not be daylight savings time' {
        $responseContent.isDayLightSavingsTime | Should -Not -Be $true
    }
    
    It 'It should not be daylight savings time another way' {
        $responseContent.isDayLightSavingsTime | Should -BeFalse
    }
}

It's probably easiest to use a real response as a template for your mock output.使用真实响应作为模拟输出的模板可能是最简单的。

Invoke-WebRequest -Method 'GET' -Uri 'http://worldclockapi.com/api/json/utc/now' | 
    Export-Clixml .\response.xml

The above command will serialize a real response from the API to a file.上面的命令会将来自 API 的真实响应序列化到文件中。

Now we can import the file to use with our mock.现在我们可以导入文件以与我们的模拟一起使用。 All it takes is to use the Mock command to define our mock.所需要的只是使用Mock命令来定义我们的模拟。

Mock

  • -CommandName : command we are mocking -CommandName : 我们正在-CommandName命令
  • -ParameterFilter : An optional filter to limit mocking behavior only to usages of CommandName where the values of the parameters passed to the command pass the filter. -ParameterFilter :一个可选的过滤器,用于将-ParameterFilter行为限制为 CommandName 的用法,其中传递给命令的参数值通过过滤器。 This ScriptBlock must return a boolean value.此 ScriptBlock 必须返回一个布尔值。
  • -MockWith : A ScriptBlock specifying the behavior that will be used to mock CommandName. -MockWith :指定将用于模拟 CommandName 的行为的 ScriptBlock。 The default is an empty ScriptBlock.默认值为空的 ScriptBlock。 It is here that we import the file to be our output.在这里,我们将文件导入为我们的输出。
Mock -CommandName Invoke-WebRequest -ParameterFilter { $Method -eq 'GET' } -MockWith { Import-Clixml .\response.xml }

Now when Invoke-WebRequest is called with -Method 'Get' our mock will be called instead and will return our object which we import using Import-CliXml (or other method - json, xml, etc.现在,当使用-Method 'Get' Invoke-WebRequest时,我们的模拟将被调用,并将返回我们使用Import-CliXml (或其他方法 - json、xml 等) Import-CliXml对象。
Note: the mock command must come before any calls to the command we are mocking.注意:mock 命令必须出现在对我们正在模拟的命令的任何调用之前。 Also note that the mock will be called even inside other functions that use the command.另请注意,即使在使用该命令的其他函数中也会调用模拟。

    BeforeAll {
        Mock -CommandName Invoke-WebRequest -ParameterFilter { $Method -eq 'GET' } -MockWith { Import-Clixml .\response.xml }

        # on this next line our mock will be called instead and will return our prepared object
        $response = Invoke-WebRequest -Method 'GET' -Uri 'http://worldclockapi.com/api/json/utc/now'
        $responseContent = $response.Content | ConvertFrom-Json
        Write-Output $responseContent
    }

I think Daniel's answer is great, but if you are working on a large or shared repository then you just need to be careful about managing those XML files too.我认为Daniel 的回答很好,但是如果您正在处理大型或共享存储库,那么您也只需要小心管理这些 XML 文件。 Another option, which I use, is to have one large Json file for all your returned objects using real responses.我使用的另一种选择是使用真实响应为所有返回的对象创建一个大型 Json 文件。 It can be imported in either BeforeAll or BeforeDiscovery depending on how your tests are structured.它可以在BeforeAllBeforeDiscovery导入,具体取决于您的测试的结构。

The reason for my supplementary answer is really just to cover error responses too, because it is important to have test cases that show how you deal with a REST call failing.我的补充答案的原因实际上也只是为了涵盖错误响应,因为拥有显示如何处理 REST 调用失败的测试用例非常重要。 Wrapping Invoke-WebRequest in your own function might be useful for returning personalised errors, handling header responses, and having constants for a site name or an allowed set of API paths.Invoke-WebRequest包装在您自己的函数中可能有助于返回个性化错误、处理标头响应以及为站点名称或一组允许的 API 路径提供常量。 Depending on the version of PowerShell, this is how I might handle a 404, for example.例如,根据 PowerShell 的版本,这就是我处理 404 的方式。

Context " When a path does not exist in the API" {
    BeforeAll {
        Mock Invoke-WebRequest {
            # Use the actual types returned by your function or directly from Invoke-WebRequest.
            if ($PSVersionTable.PSEdition -eq "Desktop") {
                $WR = New-MockObject -Type 'System.Net.HttpWebResponse'
                $Code = [System.Net.HttpStatusCode]::NotFound
                # Use Add-Member because StatusCode is a read-only field on HttpWebResponse
                $WR | Add-Member -MemberType NoteProperty -Name StatusCode -Value $Code -Force
                $Status = [System.Net.WebExceptionStatus]::ProtocolError
                $Ex = [System.Net.WebException]::new("404", $null, $Status, $WR)
            }
            else {
                $Message = [System.Net.Http.HttpResponseMessage]::new()
                $Message.StatusCode = [System.Net.HttpStatusCode]::NotFound
                $Ex = [Microsoft.PowerShell.Commands.HttpResponseException]::new("404", $Message)
            }
            throw $Ex
        } -ParameterFilter {
            $Uri -eq "http://worldclockapi.com/api/json/utc/NEVER" -and
            $Method -eq "Get"
        }

        $GetRestTimeParams = @{
            Uri   = "http://worldclockapi.com/api/json/utc/NEVER"
            Method = "Get"
        }
    }

    It " Get-RestTime should not run successfully" {
        { Get-RestTime @GetRestTimeParams } | Should -Throw
    }

    It " Get-RestTime should throw a 404 error" {
        $ShouldParams = @{
            # Use the actual types returned by your function or directly from Invoke-WebRequest.
            ExceptionType   = [System.Net.WebException]
            ExpectedMessage = "404: NotFound"
        }
        {
            Get-RestTime @GetRestTimeParams
        } | Should -Throw @ShouldParams
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM