Pester Etiketlerini Keşfetmek Yeniden Ziyaret Edildi


Dün Pester testinde etiketleri keşfetmek için yazdığım bazı PowerShell kodlarını paylaşmıştım. Güzel çalışıyor ve şikayet etmem için hiçbir nedenim yok. Ancak her zamanki gibi PowerShell'de bir şeyi yapmanın hiçbir zaman tek bir yolu yoktur. Twitter'da @FrodeFlaten'den Pester 5.2'deki yeni yapılandırma nesnesini kullanan bir yaklaşımla ilgili bir öneri aldım. Hala Pester'ın en son sürümüne ayak uydurmaya çalıştığımı rahatlıkla itiraf etmeliyim. Bu yılki hedeflerimden biri bu, bu yüzden yeni bir şeyler öğrenmek için harika bir şanstı.

PesterYapılandırması

Pester'ın önceki sürümlerinde Invoke-Pester'ı bir dizi parametre aracılığıyla kontrol edebiliyordunuz. Artık tüm test ayarlarını içeren bir yapılandırma nesnesi kullanabiliriz. New-PesterConfiguration ile varsayılan bir nesne oluşturabilirsiniz.

Öneri, Pester'ı tüm testleri çalıştırmayı atlayacak ve test nesnesini boru hattına aktaracak şekilde yapılandırmaktı. Yapılandırma nesnesi bir dizi iç içe geçmiş özelliğe sahiptir. İşte Run.

Artık yapılandırma nesnesini değiştirebilirim.

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

Özellikler açıklayıcı olmalıdır. Testi gerçekten çalıştırmadığım için herhangi bir test sonucunu görmem gerekmiyor. Invoke-Pester'ı yapılandırma nesnesini kullanarak çalıştıracağım.

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

Kullanımdan kaldırma mesajlarını bastırmak için uyarı eylemini kullanıyorum. Gerçekten gerekli değil, ancak daha temiz bir deneyim sağlıyor.

Pester Test Nesnesi

Passthru yapılandırmasını kullandığım için şöyle bir sonuç alıyorum:

Tüm bireysel testlerden yeterince kolay etiket alabiliyorum.

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

Benzersiz bir etiket listesi elde etmek için bazı filtreleme ve işlemler yapıyorum.

Ancak Tanımlama ve Bağlam gibi kapların da etiketleri olabilir.

Gördüğünüz tüm blokları ve etiketlerini tanımlayın. Ancak ilk Tanımlama bloğunun, aynı zamanda bir etiketi de olan iç içe geçmiş bir Bağlam blogu vardır. Etiketlerini tanımlamak için kaplar arasında tekrarlamam gerekiyor.

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
}

İç içe geçmiş Contex bloğunun bir “yapı” etiketi vardır. Elbette benzersiz öğeler elde etmek için bu listeyi işleyebilirim. Bu sonuçları test etiketleriyle birleştirdiğimde ihtiyacım olan her şeye sahip olmalıyım.

Gözden Geçirilmiş Bir PowerShell İşlevi

Bütün bunları aklımda tutarak fonksiyonumun gözden geçirilmiş bir versiyonunu yazdım.

#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

İşlev, boru hattına hâlâ bir nesne yazıyor ancak aynı sonuçları elde etmek için farklı bir yaklaşım kullanıyor. Ancak ödünleşimler var.

Düzenli ifadeler kullanan ilk fonksiyonum çok hızlı çalışıyor. Bu test dosyasını 0,54ms'de işledi. Pester yapılandırma nesnesini kullanan bu sürüm 0,9 ms sürer. Açıkçası bu dakika farkı üzerinde tartışmayacağım. Aslında bu yeni sürüm, gerçek test dosyasını işlediği için daha doğru olacaktır. PowerShell AST kullanan sürümüm, canlı kod ile yorumlanmış olabilecek bir şey arasında ayrım yapmayabilir (bunu emin olmak için test etmem gerekir), bu nedenle büyük olasılıkla bu yeni sürüme sadık kalacağım.

Aslında artık Pester konfigürasyon nesnesi hakkında daha fazla bilgi sahibi olduğum için birçok fikir ortaya çıkıyor. Geri döneceğime eminim.

Ah, unutmadan önce. Bu yeni işlev yalnızca PowerShell 7'de çalışır. En azından yazıldığı haliyle. Microsoft'un nesne koleksiyonlarını nasıl açtığı konusunda bazı değişiklikler yaptığını düşünüyorum, bu şekilde tag özelliğini kolayca alabiliyorum. Windows PowerShell'e takılıp kalırsanız AST sürümünü kullanmanız gerekir. Veya bu kodu Windows PowerShell'de çalışacak şekilde değiştirmekten çekinmeyin. Bu yıl benim için büyük bir hedef Windows PowerShell'i geride bırakmak. Geriye dönük uyumlulukla uğraşmak yerine zamanımı yeni şeyler öğrenerek geçirmeyi tercih ederim. Umarım benimle birlikte ilerleyebilirsin.

İlgili makaleler