2

スクリプトの先頭に関数が含まれ、その後にこれらの関数を呼び出すさまざまなコマンドが続く PowerShell .ps1 ファイルがあります。スクリプト ファイルの単体テストに Pester を使用しています。

PowerShell .ps1 スクリプト内にある関数をモックするにはどうすればよいですか?

関数をモックしようとしましたが、「コマンドが見つかりませんでした」というエラーが表示されます。

また、記述ブロックに空の「ダミー」関数を追加しようとしました。これで上記のエラーは発生しませんが、スクリプト内の関数を正しくモックしていません。

私は2つのファイルを持っています。1 つはテストを保持し、もう 1 つは関数と関数の呼び出しを保持します。以下に 2 つの例を示します。

ファイル1.ps1

Function Backup-Directory([switch]$IsError)
{
    If($IsError)
    {
        Write-Error "Error"
        Exit 1
    }
}

Backup-Directory $true

File2.Tests.ps1

$here = (Split-Path -Parent $MyInvocation.MyCommand.Path) -replace '\\test', '\main'
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
$productionFile = "$here\$sut"

Describe "File1" {

    Context "When the Back-Directory outputs an error." {

        # Arrange
        Mock Back-Directory { }
        Mock Write-Error

        # Act
        & $productionFile
        $hasSucceeded = $?

        # Assert
        It "Calls Backup-Directory" {
            Assert-MockCalled Backup-Directory -Exactly 1 -ParameterFilter {
                $IsError -eq $true
            }
        }

        It "Writes error message." {
            Assert-MockCalled Write-Error -Exactly 1 -ParameterFilter {
                 $Message -eq "Error"
            }
        }

        It "Exits with an error." {
            $hasSucceeded | Should be $false
        }
    }
}
4

1 に答える 1

5

これは不可能だと思います。少なくとも現在の実装では。しばらく前に同じ質問をしました... Pester Issue 414

しかし、その内部関数を同じディレクトリ内の別のスクリプト ファイルに分割して、単体テストとモックを作成することができます。使用できるようにするには、メイン スクリプト ファイルで関数をドット ソース化する必要があります。

Main-Function.ps1:

# Main script
function Main-Function {
    # if debugging, set moduleRoot to current directory
    if ($MyInvocation.MyCommand.Path) {
        $moduleRoot = Split-Path -Path $MyInvocation.MyCommand.Path
    }else {
        $moduleRoot = $PWD.Path
    }

    # dot source the inner function
    . "$moduleRoot\Inner-Function.ps1"

    Write-Output "This is the main script. Calling the inner function"

    Inner-Function

    Write-Output "Back in the main script"
}

内部関数.ps1:

function Inner-Function {
    Write-Output "This is the inner function"
}

Main-Function.Tests.ps1:

$moduleRoot =  Split-Path -Parent $MyInvocation.MyCommand.Path 

# Load Testing Function
. "$moduleRoot\Main-Function.ps1"

# Load Supporting Functions
. "$moduleRoot\Inner-Function.ps1"

Describe 'Main Script' {
    Mock Inner-Function { return "This is a mocked function" }

    It 'uses the mocked function' {
        (Main-Function -match "This is a mocked function") | Should Be $true
    }
}

これは非常に優れたアプローチです。なぜなら、内部関数を単体テストでき、ロジックが大きくなるにつれて、それにテストを追加するのが非常に簡単になるからです (そして、残りのスクリプト/関数から分離して実行できます)。

内部関数.Tests.ps1:

$moduleRoot =  Split-Path -Parent $MyInvocation.MyCommand.Path 

# Load Testing Function
. "$moduleRoot\Inner-Function.ps1"

Describe 'Inner Function' {
    It 'outputs some text' {
        Inner-Function | Should Be "This is the inner function"
    }
}

ここでのポイントは2つ...

現在の実行ディレクトリに関係なく、依存関数の場所を見つけています...

if ($MyInvocation.MyCommand.Path) {
        $moduleRoot = Split-Path -Path $MyInvocation.MyCommand.Path
    }else {
        $moduleRoot = $PWD.Path
    }

メイン関数と単体テスト ファイルのドット ソーシング依存関数.... "$moduleRoot\Inner-Function.ps1"

Split-Path -Path $MyInvocation.MyCommand.Pathはユーザー セッションにありますが、実行コンテキスト内から呼び出された場合は$nullそうではありません。つまり、このスクリプト/モジュールを正しくロードしている$null可能性があります。C:\users\nhudacinそうしないと、$MyInvoation変数を使用せずに、このスクリプト/モジュールが配置されている場所と同じディレクトリ内から常にこのスクリプト/モジュールを実行する必要があります。

于 2016-05-17T16:41:59.913 に答える