Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Powershell 可以使用Pester和/或Mock测试.ps1脚本吗?_Powershell_Pester - Fatal编程技术网

Powershell 可以使用Pester和/或Mock测试.ps1脚本吗?

Powershell 可以使用Pester和/或Mock测试.ps1脚本吗?,powershell,pester,Powershell,Pester,考虑一个.ps1脚本,它接受参数并进行状态更改。我想测试脚本的两个方面: 从调用者处接收参数,键入参数,并根据期望将其排序为参数集 正确进行了关键内部函数调用 这一点,考虑这个脚本,StaseCudioDimo.PS1: param([object[]]$stateChangeRequests) function ChangeSystemStateSomehow($changeRequestParameter) { # ... apply $cha

考虑一个.ps1脚本,它接受参数并进行状态更改。我想测试脚本的两个方面:

  • 从调用者处接收参数,键入参数,并根据期望将其排序为参数集
  • 正确进行了关键内部函数调用

这一点,考虑这个脚本,StaseCudioDimo.PS1:

    param([object[]]$stateChangeRequests)


    function ChangeSystemStateSomehow($changeRequestParameter)
    {
        # ... apply $changeRequestParameter to system state
    }

    $transformedRequests = $stateChangeRequests | % {
        # do some processing of requests
    }

    $transformedRequests | % {
        ChangeSystemStateSomehow $_
    }
是否可以使用纠缠和嘲弄来:

  • 截取
    $stateChangeRequests
    的值,根据调用方式验证它是否具有预期的值和形状
  • 拦截对
    changesystemstate
    的调用,以确保a)函数在测试过程中不会造成损坏(尤其是由于缺陷),以及b)函数以预期值被调用

  • 注意:我可以看到将脚本的各个部分移动到模块中有助于测试,但是对于这个问题,让我们假设脚本中的所有内容都需要保留在脚本中

    经过一些实验,我终于找到了一些令人满意的答案。在大多数情况下,答案是肯定的,但有一点诡计

    下面是测试示例,但以下是我开发测试所针对的StateChangingDemo.ps1的内容:

        [CmdletBinding(DefaultParameterSetName='SetA')]
        param(
            [Parameter(ParameterSetName='SetA')]
            [object[]]$TypeA_Requests,
    
            [Parameter(ParameterSetName='SetB')]
            [switch]$TypeB_All
        )
    
        function ChangeSystemStateSomehow($changeRequestParameter)
        {
            # ... apply $changeRequestParameter to system state
            "system state was modified"
        }
    
        $transformedRequests = $TypeA_Requests | % {
            # do some processing of requests
            $_
        }
    
        $transformedRequests | % {
            ChangeSystemStateSomehow $_
        }
    
    模拟.ps1内部的函数 如果.ps1调用需要模拟的函数(例如
    changesystemstate
    ),则在调用.ps1之前,需要存在该函数的一个版本并对其进行模拟

        Describe 'test StateChangingDemo.ps1' {
            Context 'no mock' {
                It 'needs to be mocked' {
                    & .\StateChangingDemo.ps1 | Should -Be "system state was modified"
                }
            }
    
            Context 'no mock, but placeholder function defined' {
                function ChangeSystemStateSomehow {
                    "placeholder function"
                }
    
                # Show that a function in current scope won't displace the one in the script
                It 'still needs to be mocked' {
                    & .\StateChangingDemo.ps1 | Should -Be "system state was modified"
                }
    
            }
    
            Context 'function called by script is mocked' {
                # This is required because Mock can't work before a function by the same name exists.
                # However, the mock persists even though the function is later replaced.
                function ChangeSystemStateSomehow {
                    "placeholder function"
                }
    
                Mock ChangeSystemStateSomehow {"fake execution"}
    
                It 'can have functions within mocked' {
                     & .\StateChangingDemo.ps1 | Should -Be "fake execution"
                }
            }
    
        }
    
    在脚本上测试参数解析 测试脚本的这一方面得益于两种方法

    应具有参数 第一种方法是认识到
    Should-HaveParameter
    可以直接用于脚本:

    Describe 'test StateChangingDemo.ps1' {
        Context 'no mock again' {       
            It 'has expected parameters' {
                 Get-command .\StateChangingDemo.ps1 | Should -Not -BeNullOrEmpty 
                 Get-command .\StateChangingDemo.ps1 | Should -HaveParameter TypeA_Requests -Type [object[]] 
                 Get-command .\StateChangingDemo.ps1 | Should -HaveParameter TypeB_All -Type [switch] 
            }
        }
    }
    
    第二种方法是模拟脚本本身。这并不是那么简单:

        Context 'whole script mock attempted' {
            Mock .\StateChangingDemo.ps1 {"fake script execution"}
    
            It 'cannot be mocked directly' {
                 .\StateChangingDemo.ps1 | Should -Be "system state was modified"
            }
        }
    
    上面通过的测试表明,即使我们建立了一个mock,脚本在被调用时仍然执行

    模仿脚本本身 因此,我们创建了一个函数,其实现来自将脚本视为脚本块:

        Context 'whole script wrapped' {
            Set-Item function:fnStateChangingDemo ([ScriptBlock]::Create((get-content -Raw .\StateChangingDemo.ps1)))
    
            It 'has expected parameters' {
                 Get-command fnStateChangingDemo | Should -Not -BeNullOrEmpty 
                 Get-command fnStateChangingDemo | Should -HaveParameter TypeA_Requests -Type "object[]" -Because 'it has TypeA_Requests'
                 Get-command fnStateChangingDemo | Should -HaveParameter TypeB_All -Type "switch" -Because 'it has TypeB_All'
            }
    
            Mock ChangeSystemStateSomehow {"fake execution"}
    
            It 'can still have functions within mocked when it is wrapped with a function' {
                 & fnStateChangingDemo | Should -Be "fake execution"
            }
        }
    
    上面的测试表明,该函数呈现与脚本本身相同的接口,因此我们可以以相同的方式在其上测试参数。此外,我们现在可以使用mock安全地对参数解析做出更复杂的断言:

        Context 'whole script wrapped and mocked' {       
            Set-Item function:fnStateChangingDemo ([ScriptBlock]::Create((get-content -Raw .\StateChangingDemo.ps1)))
    
            Mock fnStateChangingDemo {"fake script function execution"}
    
            It 'can be mocked when wrapped as function' {
                 fnStateChangingDemo | Should -Be "fake script function execution"
            }
    
            It 'cannot accept conflicting parameters' {
                # Using multiple parameter sets is not allowed
                {fnStateChangingDemo -TypeA_Requests 1,2,3 -TypeB_All} | Should -Throw "Parameter set cannot be resolved"
            }
        }
    
    使用更复杂的模拟体、Assert MockCalled和Assert verifiablemock以及参数过滤器,我们可以使用模拟函数包装器来设计和测试脚本的用法,而不会冒测试要求它在意外情况下执行某些实际操作的风险