Powershell 为什么我不能在Pester中测试ParameterBindingValidationException?

Powershell 为什么我不能在Pester中测试ParameterBindingValidationException?,powershell,pester,Powershell,Pester,给定具有参数验证的函数: function Test-Validation { [CmdletBinding()] param ( [Parameter()] [ValidateScript({ # Add some validation that can throw. if (-not (Test-Path -Path $_ -PathType Container)) {

给定具有参数验证的函数:

function Test-Validation {
    [CmdletBinding()]
    param (
        [Parameter()]
        [ValidateScript({
            # Add some validation that can throw.
            if (-not (Test-Path -Path $_ -PathType Container)) {
                throw "OutDir must be a folder path, not a file."
            }
            return $true
        })]
        [System.String]
        $Folder
    )
    Process {
        $Folder + " is a folder!"
    }
}
我们应该能够检查错误类型,并在Pester测试中将其设置为ExpectedType

Test-Validation -Folder C:\Temp\file.txt
Test-Validation : Cannot validate argument on parameter 'Folder'. OutDir must be a folder path, not a file.
At line:1 char:17
+ Test-Validation C:\Temp\file.txt
+                 ~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Test-Validation], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Test-Validation

$Error[0].Exception.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
False    True     ParameterBindingValidationException      System.Management.Automation.ParameterBindingException
但是,在Pester中测试时,测试失败,因为它找不到类型

$ShouldParams = @{
    Throw           = $true
    ExpectedMessage = "Cannot validate argument on parameter 'OutDir'. OutDir must be a folder path, not a file."
    ExceptionType   = ([System.Management.Automation.ParameterBindingValidationException])
}
{ Test-Validation -Folder C:\Temp\file.txt } | Should @ShouldParams

# Result
RuntimeException: Unable to find type [System.Management.Automation.ParameterBindingValidationException].

如何修复此测试,使我知道我不只是捕获任何异常类型?

无法捕获此类型的原因是因为它不是[System.Management.Automation]中的公共类。相反,您可以将-ExceptionType设置为它从[System.Management.Automation.ParameterBindingException]派生的类,您的测试现在将通过对抛出的异常类型的验证

$ShouldParams = @{
    Throw           = $true
    ExpectedMessage = "Cannot validate argument on parameter 'OutDir'. OutDir must be a folder path, not a file."
    ExceptionType   = ([System.Management.Automation.ParameterBindingException])
}
{ Test-Validation -Folder C:\Temp\file.txt } | Should @ShouldParams

无法捕获此类型的原因是它不是[System.Management.Automation]中的公共类。相反,您可以将-ExceptionType设置为它从[System.Management.Automation.ParameterBindingException]派生的类,您的测试现在将通过对抛出的异常类型的验证

$ShouldParams = @{
    Throw           = $true
    ExpectedMessage = "Cannot validate argument on parameter 'OutDir'. OutDir must be a folder path, not a file."
    ExceptionType   = ([System.Management.Automation.ParameterBindingException])
}
{ Test-Validation -Folder C:\Temp\file.txt } | Should @ShouldParams
概括一下你的观点:

由于使用从给定实例开始的对象类型在PowerShell中并不常见,因此只要派生的类型是预期公共类型的子类,实例的类型可能是非公共的这一事实通常并不明显

虽然可以通过.GetType获取对象的非公共类型,但不能通过类型文本(例如[System.Management.Automation.ParameterBindingException])引用它,例如用于Pester测试或参数声明。 您可以在任何给定实例上调用.GetType.IsPublic以检查其类型是否为public,并调用.GetType.BaseType以获取该类型的基类型-尽管您可能需要调用后一种多个类型,直到达到.IsPublic为$true的类型为止-请参阅底部的便利函数

在本例中,GetType.BaseType.FullName足以访问公共基类型:

# Provoke a non-public [System.Management.Automation.ParameterBindingValidationException] 
# exception.
try { & { param([ValidateScript({ $false })] $foo)} bar } catch { $err = $_ }

# Output the full name of the exception type underlying the
# statement-terminating error that the failed validation reported:
$err.Exception.GetType().FullName

# It is only its *base* type that is public and therefore usable as a type
# literal ([...]), such as in a Pester test.
$err.Exception.GetType().BaseType.FullName
上述收益率:

System.Management.Automation.ParameterBindingValidationException非公共 System.Management.Automation.ParameterBindingException公共基类型 下面是方便函数Get PublicType,给定任何实例,它报告实例类型的继承链中最派生的公共类型,可能是实例的类型本身:

电话示例:

获取PublicType源代码:

概括一下你的观点:

由于使用从给定实例开始的对象类型在PowerShell中并不常见,因此只要派生的类型是预期公共类型的子类,实例的类型可能是非公共的这一事实通常并不明显

虽然可以通过.GetType获取对象的非公共类型,但不能通过类型文本(例如[System.Management.Automation.ParameterBindingException])引用它,例如用于Pester测试或参数声明。 您可以在任何给定实例上调用.GetType.IsPublic以检查其类型是否为public,并调用.GetType.BaseType以获取该类型的基类型-尽管您可能需要调用后一种多个类型,直到达到.IsPublic为$true的类型为止-请参阅底部的便利函数

在本例中,GetType.BaseType.FullName足以访问公共基类型:

# Provoke a non-public [System.Management.Automation.ParameterBindingValidationException] 
# exception.
try { & { param([ValidateScript({ $false })] $foo)} bar } catch { $err = $_ }

# Output the full name of the exception type underlying the
# statement-terminating error that the failed validation reported:
$err.Exception.GetType().FullName

# It is only its *base* type that is public and therefore usable as a type
# literal ([...]), such as in a Pester test.
$err.Exception.GetType().BaseType.FullName
上述收益率:

System.Management.Automation.ParameterBindingValidationException非公共 System.Management.Automation.ParameterBindingException公共基类型 下面是方便函数Get PublicType,给定任何实例,它报告实例类型的继承链中最派生的公共类型,可能是实例的类型本身:

电话示例:

获取PublicType源代码:


好的附加信息一如既往。我打算添加一些类似的内容,以便早些时候找到最接近的公共类型。工作时间的限制意味着我必须继续前进,但我认为如果有人来看,Q&A对就足够有用了,因为参数验证在PowerShell中并不少见。我有一个问题,你能想一想为什么这个问题的例子中的问题是内部的吗?我看到建设者也主要是基地内部的。谢谢,@Ash-你的问答对非常有用,我两个都投了赞成票。我只能猜测为什么手边的类型是非公开的:也许这是只公开这些类型的一般哲学,最终用户需要与这些类型进行交互。如果从公共API的角度来看基类的成员足够多,那么派生类型可能不需要是公共的。相反,也有一些所谓的概念上是内部的,但由于技术原因是公开的。我想说这是一个相当好的猜测,一般来说是有道理的。我只是想让用户为cmdlet编写自己的验证属性,他们可能想抛出派生类,但我想我记得w
当属性派生自ValidateArgumentsAttribute时,您抛出的任何异常都是ParameterBindingValidationException的InnerException。感谢选票,我在路上的动力外壳铜牌荣誉……好补充信息一如既往。我打算添加一些类似的内容,以便早些时候找到最接近的公共类型。工作时间的限制意味着我必须继续前进,但我认为如果有人来看,Q&A对就足够有用了,因为参数验证在PowerShell中并不少见。我有一个问题,你能想一想为什么这个问题的例子中的问题是内部的吗?我看到建设者也主要是基地内部的。谢谢,@Ash-你的问答对非常有用,我两个都投了赞成票。我只能猜测为什么手边的类型是非公开的:也许这是只公开这些类型的一般哲学,最终用户需要与这些类型进行交互。如果从公共API的角度来看基类的成员足够多,那么派生类型可能不需要是公共的。相反,也有一些所谓的概念上是内部的,但由于技术原因是公开的。我想说这是一个相当好的猜测,一般来说是有道理的。我刚开始考虑用户为cmdlet编写自己的验证属性,他们可能希望抛出派生类,但我想我记得,当属性从ValidateArgumentsAttribute派生时,您抛出的任何异常都是ParameterBindingValidationException的InnerException。感谢选票,我在路上去了威力贝壳青铜荣耀…