【问题标题】:How to mock a ScriptMethod of PSCustomObject from another script?如何从另一个脚本模拟 PSCustomObject 的 ScriptMethod?
【发布时间】:2022-08-04 06:00:06
【问题描述】:

我们试图弄清楚如何使用 Pester 从另一个脚本模拟 PSCustomObject 的 ScriptMethod。

脚本1.ps1

$script2    = & $Script2PS1Path -programName $myScriptName

function Invoke-MyFunction {

$script2.outHost(\"test data\")

Get-ChildItem -Directory -Path $path -Filter \"ABC_*\"
...
...
}

脚本2.ps1

param (
    [Parameter(Mandatory=$True,ValueFromPipeline=$False,HelpMessage=\"Mandatory.\")]
    [string]$programName
)

$ErrorActionPreference = \"Stop\"

$obj = New-Object PSCustomObject
$obj | Add-Member -MemberType NoteProperty -name prog               -Value $programName
$obj | Add-Member -MemberType ScriptMethod -name outHost -Value {
    param (
        [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
        $text,

        [Parameter(Mandatory=$False,ValueFromPipeline=$True)]
        [string]$foregroundcolor,

        [Parameter(Mandatory=$False,ValueFromPipeline=$True)]
        [string]$backgroundcolor
    )

    if ($foregroundcolor -and $backgroundcolor) {
        Write-Host -Foregroundcolor $foregroundcolor -Backgroundcolor $backgroundcolor $text
    } elseif ($foregroundcolor) {
        Write-Host -Foregroundcolor $foregroundcolor $text
    } elseif ($backgroundcolor) {
        Write-Host -Backgroundcolor $backgroundcolor $text
    } else {
        Write-Host $text
    }
}

$obj

exit(0)

在上面的例子中,我们需要模拟$script2.outHost 来测试Invoke-MyFunction。模拟 $script2.outHost 的最佳方法是什么?

  • Add-Member -Force -MemberType ScriptMethod -name outHost -Value { } 允许您覆盖现有的脚本方法。
  • outHost 在哪里必须被覆盖?是从测试开始的吗?有没有办法使用 pester 来模拟 $script2 及其方法?
  • Pester 只能模拟命令。例如。你可以模拟Write-Host。这应该适用于outHost 方法。在一般情况下,您可能必须将方法调用包装到 cmdlet 中,以使它们可模拟。

标签: powershell automated-tests pester


【解决方案1】:

这实际上取决于您如何在测试中调用它 + 这实际上是脚本而不是模块(增加了一些复杂性)。

如果Script1.ps1BeforeAll 块中是点源的,并且您在It 块中运行Invoke-MyFunction,则只需覆盖cmets 中提到的ScriptMethod,例如。

It 'myTest' {
    $script2 | Add-Member -Force -MemberType ScriptMethod -name outHost -Value { 'mocked behavior' }`
    Invoke-MyFunction
}

如果Script1.ps1 真的在脚本中调用Invoke-MyFunction,那么您的测试只执行& Script1.ps1,那么您必须模拟Add-Member 并使用-ParameterFilter 定位正确的调用。前任:

脚本1.ps1

# Temp variables to make sample complete
# Script2.ps1 from OP is placed in the same folder
$Script2PS1Path = "$PSScriptRoot\Script2.ps1"
$myScriptName = 'demo'

$script2 = & $Script2PS1Path -programName $myScriptName

function Invoke-MyFunction {
    $script2.outHost('test data')
}

# Added to complete sample
Invoke-MyFunction

Script1.tests.ps1

Describe 'Script1' {
    It 'mockoutHost' {
        # Create mock for Add-Member targeted for the outHost-call
        Mock -CommandName Add-Member -ParameterFilter { $MemberType -eq 'ScriptMethod' -and $Name -eq 'outHost' } -MockWith {
            # Get real Add-Member
            $cmd = (Get-Command -Name Add-Member -CommandType Cmdlet)

            # Override incoming Value (ScriptMethod-codeblock)
            $PesterBoundParameters['Value'] = { Write-Warning "I got mocked at $((Get-Date).ToString('o'))" }

            # Call real Add-Member with modified ScriptMethod
            & $cmd @PesterBoundParameters
        }

        # Invoke Script1.ps1
        & "$PSScriptRoot\Script1.ps1"
        # Profit
    }
}

输出:

Starting discovery in 1 files.
Discovery found 1 tests in 24ms.
Running tests.
WARNING: I got mocked at 2022-08-03T21:57:04.4306325+00:00
[+] /workspaces/Pester/Samples/MockScriptMethod/Script1.Tests.ps1 100ms (52ms|25ms)
Tests completed in 101ms
Tests Passed: 1, Failed: 0, Skipped: 0 NotRun: 0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多