【问题标题】:How to mock a call to an exe file with Pester?如何使用 Pester 模拟对 exe 文件的调用?
【发布时间】:2016-06-20 15:55:23
【问题描述】:

在 PowerShell 中开发脚本,我需要调用外部可执行文件 (.exe)。目前我正在使用 TDD 方法开发这个脚本,因此我需要模拟对这个 .exe 文件的调用。

我试试这个:

Describe "Create-NewObject" {
    Context "Create-Object" {
        It "Runs" {
            Mock '& "c:\temp\my.exe"' {return {$true}}
            Create-Object| Should Be  $true
        }
    }
}

我收到了这样的回复:

Describing Create-NewObject
   Context Create-Object
    [-] Runs 574ms
      CommandNotFoundException: Could not find Command & "C:\temp\my.exe"
      at Validate-Command, C:\Program Files\WindowsPowerShell\Modules\Pester\Functions\Mock.ps1: line 801
      at Mock, C:\Program Files\WindowsPowerShell\Modules\Pester\Functions\Mock.ps1: line 168
      at <ScriptBlock>, C:\T\Create-NewObject.tests.ps1: line 13
Tests completed in 574ms
Passed: 0 Failed: 1 Skipped: 0 Pending: 0 Inconclusive: 0

有没有办法模拟这种调用而不将它们封装在函数中?

【问题讨论】:

    标签: unit-testing powershell mocking pester


    【解决方案1】:

    我找到了一种方法来模拟对这个可执行文件的调用:

    function Create-Object
    {
       $exp = '& "C:\temp\my.exe"'
       Invoke-Expression -Command $exp
    }
    

    使用 mock 的测试应该如下所示:

    Describe "Create-NewObject" {
        Context "Create-Object" {
            It "Runs" {
                Mock Invoke-Expression {return {$true}} -ParameterFilter {($Command -eq '& "C:\temp\my.exe"')
                Create-Object| Should Be  $true
            }
        }
    }
    

    【讨论】:

    • 这也是我想出的最佳选择,但我相信Invoke-Experssion 被认为是“代码味道”。
    【解决方案2】:

    是的,很遗憾,从 Pester 4.8.1 开始:

    • 不能通过完整路径模拟外部可执行文件(例如,C:\Windows\System32\cmd.exe
    • 可以通过文件名模拟它们(例如,cmd),但请注意,在较旧的 Pester 版本中,模拟仅在显式使用的调用中调用.exe 扩展名(例如,cmd.exe) - 请参阅 this (obsolete) GitHub issue

    Your own workaround有效,但涉及Invoke-Expression,比较尴尬; Invoke-Expression should generally be avoided

    这是一个使用辅助函数Invoke-External 的解决方法,它包装外部程序的调用,并且作为一个函数,它本身可以被模拟,使用-ParameterFilter 按可执行路径过滤:

    在您的代码中,定义Invoke-External 函数,然后使用它来调用c:\temp\my.exe

    # Helper function for invoking an external utility (executable).
    # The raison d'être for this function is to allow 
    # calls to external executables via their *full paths* to be mocked in Pester.
    function Invoke-External {
      param(
        [Parameter(Mandatory=$true)]
        [string] $LiteralPath,
        [Parameter(ValueFromRemainingArguments=$true)]
        $PassThruArgs
      )
      & $LiteralPath $PassThruArgs
    }
    
    # Call c:\temp\my.exe via invoke-External
    # Note that you may pass arguments to pass the executable as usual (none here):
    Invoke-External c:\temp\my.exe
    

    然后,在 Pester 测试中模拟对 c:\temp\my.exe 的调用:

    Mock Invoke-External -ParameterFilter { $LiteralPath -eq 'c:\temp\my.exe' } `
      -MockWith { $true }
    

    注意:如果您的代码中只有一个调用外部可执行文件,则可以省略
    -ParameterFilter 参数。

    【讨论】:

      【解决方案3】:

      我尝试了这个,似乎可以工作。

      $PathToExe = 'C:\Windows\System32\wevtutil.exe'
      New-Item -Path function: -Name $PathToExe -Value { ... }
      Mock $PathToExe { ... }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多