为什么Pester没有使用陷阱捕获错误

时间:2016-04-15 16:24:29

标签: powershell error-handling pester

我想知道为什么在运行此脚本时会出现以下行为。我在PowerShell ISE(v4主机)中加载了脚本并加载了Pester模块。我按F5运行脚本。

function Test-Pester {
  throw("An error")
}

Describe "what happens when a function throws an error" {

  Context "we test with Should Throw" {

    It "Throws an error" {
      { Test-Pester } | Should Throw
    }
  }

  Context "we test using a try-catch construct" {

    $ErrorSeen = $false
    try {
      Test-Pester
    }
    catch {
      $ErrorSeen = $true
    }

    It "is handled by try-catch" {
      $ErrorSeen | Should Be $true
    }
  }

  Context "we test using trap" {

    trap {
      $ErrorSeen = $true
    }

    $ErrorSeen = $false

    Test-Pester

    It "is handled by trap" {
      $ErrorSeen | Should Be $true
    }
  }
}

然后我得到以下输出:

Describing what happens when a function throws an error
   Context we test with Should Throw
    [+] Throws an error 536ms
   Context we test using a try-catch construct
    [+] is handled by try-catch 246ms
   Context we test using trap
An error
At C:\Test-Pester.ps1:2 char:7
+       throw("An error")
+       ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (An error:String) [], RuntimeException
    + FullyQualifiedErrorId : An error

    [-] is handled by trap 702ms
      Expected: {True}
      But was:  {False}
      at line: 40 in C:\Test-Pester.ps1
      40:           $ErrorSeen | Should Be $true

问题

为什么trap{}显然没有在最终测试中运行?

2 个答案:

答案 0 :(得分:2)

以下是基于@PetSerAl和@Eris的评论/建议答案的问题的两种解决方案。我也阅读并赞赏这个问题的答案:

Why are variable assignments within a Trap block not visible outside it?

解决方案1 ​​

虽然可以在陷阱中读取脚本中设置的变量,但是在陷阱中执行的任何操作都发生在该变量的副本中,即仅在陷阱本地的范围内。在此解决方案中,我们将引用评估为$ErrorSeen,以便在设置变量的值时,实际上设置父范围中存在的变量的值。

向陷阱添加continue会抑制ErrorRecord的详细信息,从而清除测试的输出。

Describe "what happens when a function throws an error" {
  Context "we test using trap" {

    $ErrorSeen = $false

    trap {
      Write-Warning "Error trapped"
      ([Ref]$ErrorSeen).Value = $true
      continue
    }

    Test-Pester

    It "is handled by trap" {
      $ErrorSeen | Should Be $true
    }
  }
}

解决方案2

与第一个解决方案一样,问题可以通过在$ErrorSeen变量(1)首次创建时明确设置范围来解决,(2)在{{1}中使用时}。我在这里使用了脚本范围,但Global似乎也有效。

同样的原则适用于此:我们需要避免陷阱中变量的更改仅发生在变量的本地副本上的问题。

trap {}

答案 1 :(得分:1)

根据this blog,您需要告诉陷阱对控制流程做些什么:

  

您注意到的事情是,当您以脚本形式运行时,您将收到错误消息和红色PowerShell错误消息。

. 'C:\Scripts\test.ps1'
Something terrible happened!
Attempted to divide by zero.
At C:\Scripts\test.ps1:2 Char:3
+ 1/ <<<< null
  

这是因为你的Trap并没有真正处理异常。要处理异常,您需要将“Continue”语句添加到陷阱中:

trap { 'Something terrible happened!'; continue }
1/$null
  

现在,陷阱按预期工作。它执行您在陷阱脚本块中指定的任何内容,并且PowerShell不再能够查看异常。您不再收到红色错误消息。