当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 重新发现 Pester 标签

作者:精品下载站 日期:2024-12-14 08:05:26 浏览:14 分类:玩电脑

重新发现 Pester 标签


昨天,我分享了一些我编写的用于在 Pester 测试中发现标签的 PowerShell 代码。它运作良好,我没有理由抱怨。但与往常一样,在 PowerShell 中做某事从来不存在简单的一种方法。我从 Twitter 上的 @FrodeFlaten 那里得到了关于使用 Pester 5.2 中新配置对象的方法的建议。我承认我仍在跟上最新版本的 Pester。这是我今年的目标之一,所以这是学习新东西的好机会。

Pester配置

在 Pester 的早期版本中,您可以通过一组参数来控制 Invoke-Pester。现在我们可以使用包含所有测试设置的配置对象。您可以使用 New-PesterConfiguration 创建默认对象。

[玩转系统] 重新发现 Pester 标签

建议将 Pester 配置为跳过运行所有测试并将测试对象传递到管道。配置对象具有一组嵌套属性。这里是《运行》。

[玩转系统] 重新发现 Pester 标签

我现在可以修改配置对象。

$config.Run.SkipRun = $true
$config.run.path = 'C:\scripts\PSFunctionTools\tests\psfunctiontools.tests.ps1'
$config.run.PassThru = $True
$config.Output.Verbosity = "none"

这些属性应该是不言自明的。由于我没有真正运行测试,因此我不需要查看任何测试结果。我将使用配置对象运行 Invoke-Pester。

$r = Invoke-Pester -Configuration $config -WarningAction SilentlyContinue

我正在使用警告操作来抑制任何弃用消息。并不是真的必要,但它可以带来更干净的体验。

纠缠测试对象

因为我使用了 Passthru 配置,所以得到如下结果:

[玩转系统] 重新发现 Pester 标签

我可以很容易地从所有单独的测试中获取标签。

 $($r.tests.tag).Where({$_}).foreach({$_.toLower()}) | Select-Object -unique

[玩转系统] 重新发现 Pester 标签

我正在进行一些过滤和处理以获得唯一的标签列表。

但是像Describe和Context这样的容器也可以有标签。

[玩转系统] 重新发现 Pester 标签

你看到的都是Describe块和它们的标签。但是第一个描述块有一个嵌套的上下文博客,它也有一个标签。我需要递归容器来识别它们的标签。

function _recurseBlock {
    Param([object]$block)
    $block.tag
    if ($block.blocks) {
        foreach ($item in $block.blocks) {
            _recurseBlock $item
        }
    }
}

foreach ($block in $r.containers.blocks) {
    _recurseBlock $block
}

[玩转系统] 重新发现 Pester 标签

嵌套的Contex块有一个“结构”标签。当然,我可以处理这个列表以获得独特的项目。将这些结果与测试标签结合起来,我应该拥有我需要的一切。

修改后的 PowerShell 函数

考虑到所有这些,我编写了函数的修订版本。

#requires -version 7.1
#requires -module @{ModuleName = 'Pester';ModuleVersion='5.2'}

Function Get-PesterTag {
    #thanks to https://twitter.com/FrodeFlaten for the suggestion
    [cmdletbinding()]
    [OutputType("pesterTag")]
    Param(
        [Parameter(
            Position = 0,
            Mandatory,
            HelpMessage = "Specify a Pester test file",
            ValueFromPipeline
        )]
        [ValidateScript({
                #validate file exits
                if (Test-Path $_) {
                    #now test for extension
                    if ($_ -match "\.ps1$") {
                        $True
                    }
                    else {
                        Throw "The filename must end in '.ps1'."
                    }
                }
                else {
                    Throw "Cannot find file $_."
                }
            })]
        [string]$Path
    )

    Begin {
        Write-Verbose "[$((Get-Date).TimeofDay) BEGIN  ] Starting $($myinvocation.mycommand)"
        $config = New-PesterConfiguration
        $config.Run.SkipRun = $true
        $config.run.PassThru = $True
        $config.Output.Verbosity = "none"

        #a private helper function to recurse through Describe and Context test blocks
        function _recurseBlock {
            Param([object]$block)
            $block.tag
            if ($block.blocks) {
                foreach ($item in $block.blocks) {
                    _recurseBlock $item
                }
            }
        }
        #Initiate a list to hold tags
        $list = [system.collections.generic.list[string]]::new()

    } #begin

    Process {
        $Path = Convert-Path $path
        Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting tags from $Path"
        $config.run.path = $path
        Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Invoking Pester"
        $r = Invoke-Pester -Configuration $config -WarningAction SilentlyContinue

        #get Test tags and add unique items to the list
        $($r.tests.tag).Where({ $_ }).foreach({
                $t = $_.toLower();
                if (-Not ($list.Contains($t))) {
                    $list.add($t)
                } })

        #get block tags
        foreach ($block in $r.containers.blocks) {
            _recurseBlock $block | ForEach-Object {
                $t = $_.toLower()
                #add item to the list if not already there
                if (-Not ($list.Contains($t))) {
                    $list.add($t)
                }
            } #foreach tag
        } #foreach block

        if ($list.count -gt 0) {
            [pscustomobject]@{
                PSTypename = "pesterTag"
                Path       = $Path
                Tags       = $List | Sort-Object
            }
        }
        else {
            Write-Warning "No tags found in $Path"
        }
    } #process

    End {
        Write-Verbose "[$((Get-Date).TimeofDay) END    ] Ending $($myinvocation.mycommand)"
    } #end

} #close Get-PesterTag

[玩转系统] 重新发现 Pester 标签

该函数仍然将对象写入管道,但它使用不同的方法来获得相同的结果。然而,这也是需要权衡的。

我的第一个使用正则表达式的函数运行得非常快。它在 0.54 毫秒内处理了这个测试文件。使用 Pester 配置对象的此版本需要 0.9 毫秒。坦率地说,我不会为这一微小的差异而争论。事实上,这个新版本将更加准确,因为它正在处理实际的测试文件。我使用 PowerShell AST 的版本可能无法区分实时代码和可能已被注释掉的代码(我必须对其进行测试才能确定),因此我很可能会坚持使用这个新版本。

事实上,现在我对 Pester 配置对象有了更多的了解,许多想法正在酝酿之中。我有信心我会回来的。

哦,在我忘记之前。这个新函数仅在 PowerShell 7 中有效。至少按照编写的那样。我认为微软在如何展开对象集合方面做了一些改变,这就是我可以轻松获取标签属性的方式。如果您无法使用 Windows PowerShell,则需要使用 AST 版本。或者随意修改此代码以在 Windows PowerShell 中工作。我今年的一个大目标是抛弃 Windows PowerShell。我宁愿把时间花在学习新事物上,而不是在向后兼容性上苦苦挣扎。我希望你能和我一起前进。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯