Python的doctest模块是否有等效的PowerShell?



我刚刚遇到了 Python 中的doctest模块,它可以帮助您针对嵌入在 Python 文档字符串中的示例代码执行自动化测试。这最终有助于确保 Python 模块的文档与模块的实际行为之间的一致性。

PowerShell中是否有等效的功能,因此我可以在PowerShell内置帮助的.EXAMPLE部分中测试示例?

这是我尝试做的一个例子:

function MyFunction ($x, $y) {
<#
.EXAMPLE
> MyFunction -x 2 -y 2
4
#>
return $x + $y
}
MyFunction -x 2 -y 2

你可以这样做,尽管我不知道有任何多合一的内置方法可以做到这一点。

方法 1 - 创建脚本块并执行它

帮助文档是一个对象,因此可以利用它来索引示例及其代码。下面是我能想到的最简单的示例,它执行您的示例代码。

我不确定这是否是doctest所做的 - 这对我来说似乎有点危险,但这可能是你所追求的!这是最简单的解决方案,我认为会给你最准确的结果。

Function Test-Example {
param (
$Module
)
# Get the examples
$examples = Get-Help $Module -Examples
# Loop over the code of each example
foreach ($exampleCode in $examples.examples.example.code) {
# create a scriptblock of your code
$scriptBlock = [scriptblock]::Create($exampleCode)
# execute the scriptblock
$scriptBlock.Invoke()
}
}

方法 2 - 解析示例/函数并进行手动断言

我认为一个可能更好的方法是解析您的示例并解析函数以确保其有效。缺点是这可能会变得非常复杂,特别是如果您正在编写复杂的函数。

下面是一些代码,用于检查示例是否具有正确的函数名称、参数和有效值。它可能会被重构(第一次处理[System.Management.Automation.Language.Parser]),并且根本不处理高级功能。

如果你关心像MandatoryParameterSetNameValidatePattern等,这可能不是一个好的解决方案,因为它需要大量的扩展。

Function Check-Example {
param (
$Function
)
# we'll use this to get the example command later
# source: https://vexx32.github.io/2018/12/20/Searching-PowerShell-Abstract-Syntax-Tree/
$commandAstPredicate = {
param([System.Management.Automation.Language.Ast]$AstObject)
return ($AstObject -is [System.Management.Automation.Language.CommandAst])
}
# Get the examples
$examples = Get-Help $Function -Examples
# Parse the function
$parsedFunction = [System.Management.Automation.Language.Parser]::ParseInput((Get-Content Function:$Function), [ref]$null, [ref]$null)
# Loop over the code of each example
foreach ($exampleCode in $examples.examples.example.code) {
# parse the example code
$parsedExample = [System.Management.Automation.Language.Parser]::ParseInput($exampleCode, [ref]$null, [ref]$null)
# get the command, which gives us useful properties we can use
$parsedExampleCommand = $parsedExample.Find($commandAstPredicate,$true).CommandElements
# check the command name is correct
"Function is correctly named: $($parsedExampleCommand[0].Value -eq $Function)"
# loop over the command elements. skip the first one, which we assume is the function name
foreach ($element in ($parsedExampleCommand | select -Skip 1)) {
"" # new line
# check parameter in example exists in function definition
if ($element.ParameterName) {
"Checking parameter $($element.ParameterName)"
$parameterDefinition = $parsedFunction.ParamBlock.Parameters | where {$_.Name.VariablePath.Userpath -eq $element.ParameterName}
if ($parameterDefinition) {
"Parameter $($element.ParameterName) exists"
# store the parameter name so we can use it to check the value, which we should find in the next loop
# this falls apart for switches, which have no value so they'll need some additional logic
$previousParameterName = $element.ParameterName
}
}
# check the value has the same type as defined in the function, or can at least be cast to it.
elseif ($element.Value) {
"Checking value $($element.Value) of parameter $previousParameterName"
$parameterDefinition = $parsedFunction.ParamBlock.Parameters | where {$_.Name.VariablePath.Userpath -eq $previousParameterName}
"Parameter $previousParameterName has the same type: $($element.StaticType.Name -eq $parameterDefinition.StaticType.Name)"
"Parameter $previousParameterName can be cast to correct type: $(-not [string]::IsNullOrEmpty($element.Value -as $parameterDefinition.StaticType))"
}
else {
"Unexpected command element:"
$element
}
}
}
}

方法 3 - 使用 Pester(可能超出范围)

我认为这个有点跑题,但值得一提。Pester是PowerShell的测试框架,具有在这里可能会有所帮助的功能。你可以有一个通用测试,它将脚本/函数作为参数,并针对解析的示例/函数运行测试。

这可能涉及像方法 1 中那样执行脚本或像方法 2 中那样检查参数。Pester 有一个HaveParameter断言,允许你检查有关函数的某些事情。

HaveParameter文档,从上面的链接复制:

Get-Command "Invoke-WebRequest" | Should -HaveParameter Uri -Mandatory
function f ([String] $Value = 8) { }
Get-Command f | Should -HaveParameter Value -Type String
Get-Command f | Should -Not -HaveParameter Name
Get-Command f | Should -HaveParameter Value -DefaultValue 8
Get-Command f | Should -HaveParameter Value -Not -Mandatory

最新更新