Как имитировать команду, вызываемую дважды с разными параметрами и разными результатами

У меня есть функция PowerShell, которую я хочу протестировать с помощью Pester:

function Install-RequiredModule (
    [string]$ModuleName,
    [string]$RepositoryName,
    [string]$ProxyUrl
    )
{
    # Errors from Install-Module are non-terminating.  They won't be caught using  
    # try - catch.  So check $Error instead.
    # Clear errors so we know if one shows up it must have been due to Install-Module.
    $Error.Clear()

    # Want to fail silently, without displaying anything in console to scare the user, 
    # because it's valid for Install-Module to fail for a user behind a proxy server.
    Install-Module -Name $ModuleName -Repository $RepositoryName `
        -ErrorAction SilentlyContinue -WarningAction SilentlyContinue

    if ($Error.Count -eq 0)
    {
        # throw 'NO error'
        return
    }

    # There was an error so try again, this time with proxy details.

    $proxyCredential = Get-Credential -Message 'Please enter credentials for proxy server'

    # No need to Silently Continue this time.  We want to see the error details.
    $Error.Clear()

    Install-Module -Name $ModuleName -Repository $RepositoryName `
        -Proxy $ProxyUrl -ProxyCredential $proxyCredential

    if ($Error.Count -gt 0)
    {
        throw $Error[0]
    }

    if (-not (Get-InstalledModule -Name $ModuleName -ErrorAction SilentlyContinue))
    {
        throw "Unknown error installing module '$ModuleName' from repository '$RepositoryName'."
    }

    Write-Output "Module '$ModuleName' successfully installed from repository '$RepositoryName'."
}

Эта функция может дважды вызвать Install-Module. Сначала он пытается без учетных данных прокси, как если бы у него был прямой доступ к Интернету. Если это не удается, он пытается снова, на этот раз с учетными данными прокси.

Как я могу проверить эту функциональность с помощью Pester?

Я читал на форумах PowerShell, здесь, что я должен иметь возможность дважды издеваться над одной и той же командой с разными фильтрами параметров. Вот что я пробовал:

function ExecuteInstallRequiredModule ()
{
    Install-RequiredModule -ModuleName 'TestModule' -RepositoryName 'TestRepo' `
        -ProxyUrl 'http://myproxy'
}

Describe 'Install-RequiredModule' {

    $securePassword = "mypassword" | 
        ConvertTo-SecureString -asPlainText -Force
    $psCredential = New-Object System.Management.Automation.PSCredential  ('MyUserName', $securePassword)
    Mock Get-Credential { return $psCredential }

    # Want to add an error to $Error without it being written to the host.
    Mock Install-Module { Write-Error "Some error" -ErrorAction SilentlyContinue } `
        -ParameterFilter { $Name -eq  'TestModule' -and $Repository -eq 'TestRepo' -and $ErrorAction -eq 'SilentlyContinue' -and $WarningAction -eq 'SilentlyContinue'}
    Mock Install-Module { return $Null } `
        -ParameterFilter { $Name -eq  'TestModule' -and $Repository -eq 'TestRepo' -and $Proxy -eq 'http://myproxy' -and $ProxyCredential -eq $psCredential }

    Mock Get-InstalledModule { return @('Non-null text') }

    It 'attempts to install module a second time if first attempt fails' {
        ExecuteInstallRequiredModule
        #Assert-VerifiableMock
        #Assert-MockCalled Install-Module -Scope It -Times 2
    }
}

Раскомментируя строку в тестируемой функции, которая говорит # throw 'NO error', я обнаружил, что $ Error.Count равен 0 после первого вызова Install-Module. Таким образом, макет, который создает непрекращающуюся ошибку, не вызывается, и функция возвращается до второго вызова Install-Module.


person Simon Tewsi    schedule 25.06.2019    source источник


Ответы (3)


Проблема, похоже, в том, что Pester блокирует фильтрацию по общим параметрам, поэтому использование «ErrorAction» и т. Д. Приводит к сбою фильтра.

Вы можете увидеть, как параметры удаляются из фиктивных функций примерно в строке 254 макета кода Pester: Mock.ps1

Кроме того, тестирование этого удаления является одним из собственных модульных тестов Pester (строка 283): Mock.tests.ps1

person boxdog    schedule 25.06.2019

Вы можете вызвать команду install-module с -ErrorAction Stop внутри цикла перехвата попыток.

try
{
    #run with no credentials
    Install-Module -Name $ModuleName -Repository $RepositoryName -ErrorAction stop -WarningAction SilentlyContinue
}
catch
{
    #when fails, run with proxy credentials
    Install-Module -Name $ModuleName -Repository $RepositoryName -Proxy $ProxyUrl -ProxyCredential $proxyCredential
}

У вас может быть несколько блоков catch{} для одной и той же команды try, которая будет обнаруживать различные типы сбоев и выполнять блок сценария по вашему выбору.

person Sid    schedule 25.06.2019

Для всех, кто оказался в подобной ситуации, вот последняя версия теста, которая сработала:

function Install-RequiredModule (
    [string]$ModuleName,
    [string]$RepositoryName,
    [string]$ProxyUrl
    )
{
    try
    {
        Install-Module -Name $ModuleName -Repository $RepositoryName `
            -ErrorAction Stop

        return
    }
    catch {}

    # There was an error so try again, this time with proxy details.

    $proxyCredential = Get-Credential -Message 'Please enter credentials for proxy server'

    # No need to Silently Continue this time.  We want to see the error details.
    $Error.Clear()

    Install-Module -Name $ModuleName -Repository $RepositoryName `
        -Proxy $ProxyUrl -ProxyCredential $proxyCredential

    if ($Error.Count -gt 0)
    {
        throw $Error[0]
    }

    if (-not (Get-InstalledModule -Name $ModuleName -ErrorAction SilentlyContinue))
    {
        throw "Unknown error installing module '$ModuleName' from repository '$RepositoryName'."
    }

    Write-Output "Module '$ModuleName' successfully installed from repository '$RepositoryName'."
}

#region Tests *************************************************************************************

function ExecuteInstallRequiredModule ()
{
    Install-RequiredModule -ModuleName 'TestModule' -RepositoryName 'TestRepo' `
        -ProxyUrl 'http://myproxy'
}

Describe 'Install-RequiredModule' {

    $securePassword = "mypassword" | 
        ConvertTo-SecureString -asPlainText -Force
    $psCredential = New-Object System.Management.Automation.PSCredential  ('MyUserName', $securePassword)
    Mock Get-Credential { return $psCredential }

    Mock Install-Module { Write-Error "Some error" }
    Mock Install-Module { return $Null } -ParameterFilter { $Proxy -ne $Null -and $ProxyCredential -ne $Null }

    Mock Get-InstalledModule { return @('Non-null text') }

    It 'attempts to install module a second time, with proxy, if first attempt fails' {
        ExecuteInstallRequiredModule  
        Assert-MockCalled Install-Module -Scope It -Times 2 -Exactly
    }
}

#endregion
person Simon Tewsi    schedule 28.06.2019