【问题标题】:Can Pester mock an exception?Pester 可以模拟异常吗?
【发布时间】:2017-08-08 16:34:56
【问题描述】:

我正在处理一些 Pester 测试用例,并且正在查看 CodeCoverage 结果。在大多数代码包含 try/catch 的测试用例中,我们得到 0% 的 catch 覆盖率。这是一个例子:

function Test-Is64Bit()
{

    $Result = $false

    try
    {
        if ((Get-WmiObject -Class "Win32_OperatingSystem").OSArchitecture -eq '64-bit')
        {
            $Result = $true
        }
    }
    catch
    {
        Write-Error $_.Exception | Format-List -Force
    }

    return $Result
}

很容易模拟 Get-WmiObject 返回值来测试 $true 条件。

我已经尝试了许多想法来模拟 Get-WmiObject 的异常,但在每种情况下,异常都会传递到控制台,而不是被 Pester 捕获并通过测试。下面是我想出的最好的,但它仍然不起作用。

Context "Unit tests for Get-WmiObject exception" {
    # mock the Get-WmiObject cmdlet for unit testing
    Mock Get-WmiObject {
        Throw
    } -ParameterFilter { $Class -And $Class -eq 'Win32_OperatingSystem' }

    It "Function test passes" {
        { Test-Is64Bit } | Should Be $false
        Assert-MockCalled Get-WmiObject -Scope It -Exactly -Times 1
    }
}

此测试结果:

     Context Unit tests for Get-WmiObject error
      [-] Function test passes 138ms
        Expected: {False}
        But was:  { Test-Is64Bit }
        at line: 62 in .\Tests\Test-Is64Bit.Tests.ps1
        62:                             { Test-Is64Bit } | Should Be $false
Tests completed in 590ms
Tests Passed: 4 Failed: 1 Skipped: 0 Pending: 0 Inconclusive: 0

Code coverage report:
Covered 80.00 % of 10 analyzed Commands in 1 File.
Missed commands:

File             Function     Line Command
----             --------     ---- -------
Test-Is64Bit.ps1 Test-Is64Bit   38 Write-Error $_.Exception
Test-Is64Bit.ps1 Test-Is64Bit   38 Format-List -Force

有什么方法可以模拟 Get-WmiObject 抛出的异常,以便我们可以让 Pester 陷入困境并最终实现 100% 的代码覆盖率?

我当前的测试代码寻找异常

Context "Unit tests for Get-WmiObject exception" {
    # mock the Get-WmiObject cmdlet for unit testing
    Mock Get-WmiObject {
        Throw 'Some Error'
    } -ParameterFilter { $Class -And $Class -eq 'Win32_OperatingSystem' }

    It 'Get-WmiObject should throw' {
        { Get-WmiObject -Class 'Win32_OperatingSystem' } | Should Throw 'Some Error'
    }

    It "Throws exception" {
        { Test-Is64Bit } | Should Throw 'Some Error'
        Assert-MockCalled Get-WmiObject -Scope It -Exactly -Times 1
    }
}

上面的代码结果如下:

     Context Unit tests for Get-WmiObject exception
       [+] Get-WmiObject should throw 89ms
 Test-Is64Bit : System.Management.Automation.RuntimeException: Some Error At
 C:\ONESolutionFinance\Main\ReleaseManagement\PowerShell-Module\SPSNoDeps\Tests\Test-Is64Bit.Tests.ps1:66
 char:7
 +                 { Test-Is64Bit } | Should Throw 'Some Error'
 +                   ~~~~~~~~~~~~
     + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
     + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-Is64Bit

       [-] Throws exception 51ms
         Expected: the expression to throw an exception with message {Some Error}, an exception was not raised, message was {}
             from line:2 char:5
             +                 Throw 'Some Error'
             +                 ~~~~~~~~~~~~~~~~~~
         at line: 66 in C:\ONESolutionFinance\Main\ReleaseManagement\PowerShell-Module\SPSNoDeps\Tests\Test-Is64Bit.Tests.ps1
         66:                             { Test-Is64Bit } | Should Throw 'Some Error'

测试 $false 会返回:

    Context Unit tests for Get-WmiObject exception
      [+] Get-WmiObject should throw 162ms
Test-Is64Bit : System.Management.Automation.RuntimeException: Some Error
At C:\ONESolutionFinance\Main\ReleaseManagement\PowerShell-Module\SPSNoDeps\Tests\Test-Is64Bit.Tests.ps1:66 char:5
+                 Test-Is64Bit | Should Be $false
+                 ~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-Is64Bit

      [+] Throws exception 92ms

【问题讨论】:

    标签: unit-testing powershell mocking try-catch pester


    【解决方案1】:

    是的,它可以!这是一个例子:

    Describe 'Mock an exception' {
        Mock Get-WMIObject { Throw 'some error' }
    
        It 'Get-WMIObject should throw' {
            {Get-WMIObject -class someclass} | Should Throw 'some error'
        }
    }
    

    我认为您的代码不起作用,因为:

    { Test-Is64Bit } | Should Be $false
    

    应该是:

     { Test-Is64Bit } | Should Throw
    

    当您使用 Should Throw 时,您在 Should 之前使用 ScriptBlock { }

    【讨论】:

    • 我已经更新了我的原始帖子以使问题更加清晰。模拟 Get-WmiObject 异常并在 Pester 中测试异常可以正常工作。但是有没有办法测试 Test-Is64Bit 函数并让 Get-WmiObject 抛出异常,以便 Pester 测试落入 Test-Is64Bit 内部的陷阱中。我仍然得到失败的测试,并看到控制台抛出异常。
    • 您是否在函数中的 get-wmiobject 上使用 -erroraction stop?如果不是,也许你的 catch 永远不会被调用?
    • 我已经尝试过在 Get-WmiObject 上使用和不使用 -ErrorAction 停止。控制台中显示了相同的异常。
    • 您还在测试 $false 结果,而不是 throw 吗?
    • 或者如果你的 try catch 意味着它不会抛出异常而是返回 false,那么你需要你的测试是这样的:Test-Is64Bit | Should Be $false
    【解决方案2】:
    function Test-LocalFile
    {
        param (
            [string]
            $filepath
        )
        try {
            $FileInfo = get-item -Path $filepath -ErrorAction SilentlyContinue
            if ($FileInfo.getType().Name -eq "FileInfo") {
                return $true
            }
        } catch {
    
             Write-Error -Message "$($_.Exception.Message)"
             Throw
        }
    }
    

    这里是上层定义的函数如何处理异常的整体解决方案

    Describe "Unit testing for exception handling" {
        Context "unit test showing exception"{
    
        #arrange
        Mock Write-Error{}
        Mock get-item  {
               Throw 'some error'
        }
    
        #act
        Write-Error 'some error'
        #assert
        It "test-Local FileThrows exception" {
                 {Test-LocalFile -filepath test.txt}  | Should Throw 'some error'
                Assert-MockCalled get-item -Scope It -Exactly -Times 1
            }
        }
    }
    

    【讨论】:

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