1


0

Powershellのスタックトレースは壊れていますか?

私はPowerShellでシンプルなユニットテストハーネスを書いています

アサート関数がスクリプトブロックをパラメーターとして取るようにハーネスを設計し、ハーネスがアサート関数内からコードを実行し、例外がテスト失敗としてスローされるようにします。

テストが失敗した場合、テストが失敗した単体テストの行を返します。 私の計画は、各アサートメソッドの開始時にスタックトレース(Get-PSCallStack)を取得してこれを行い、アサート関数が呼び出された行に対応するはずの2番目のスタックフレームの情報を使用することでした。

実際には、powershellから返された情報は間違っているように見えました。 2番目のスタックフレームは期待どおり正しいファイルを参照しますが、アサートメソッドでGet-PSCallStackを呼び出した行番号を常に提供します。 この数は、指定されたファイルの行数(つまり、 場所は「ScriptFile.ps1 line 88」として指定されていますが、ファイルには20行しかありません)。

PowerShellのスタックトレースに問題がありますか、またはここで理解していないものがありますか?

編集

リクエストに応じて、同じ結果を生成する例を投稿しています

Tester.ps1

#File 1 (Tester.ps1)
#Creates the tester object

$tester = (New-Object PSObject);

$tester | Add-Member -MemberType ScriptMethod -Name AssertTrue -Value {
    param($expression);

    $stackFrame = (GEt-PSCallStack)[1];

    try{
        $result = &$expression;
        if($result -eq $true){
            $this.LogPass();
        }else{
            $this.LogFailure("Evaluation Failed expected ""$true"" got ""$false""", $stackFrame);
        }
    }catch [Exception]{
        $this.LogFailure("Unexpected exception encountered", $stackFrame);
    }
}

$tester | Add-Member -MemberType ScriptMethod -Name LogPass -Value {
    #Do nothing
};

$tester | Add-Member -MemberType ScriptMethod -Name LogFailure -Value {
    param($message, $stackFrame);
    "Failure Encounterd";
    "Command: $($stackFrame.Command)"
    "Location: $($stackFrame.Location)";
    "Message: $message";
}

return $tester;

TestCase.ps1

#File 2 (TestCase.ps1)
#Runs the tests using the tester object

$tester = &(Resolve-Path "Tester.ps1");

function TestFailure($tester){
    $expression = {$false};
    $tester.AssertTrue($expression);
}

TestFailure($tester);

TestCase.ps1の行7でアサートが呼び出され、Tester.ps1の行9で呼び出しスタックがキャプチャされます。

この版画

Failure Encounterd
Command: TestFailure
Location: Tester.ps1: Line 9
Message: Evaluation Failed expected "True" got "False"

コマンドは正しいが、ファイルと行の両方が間違っている

スタックトレースの次のフレームは、TestFailure()が「TestCase.ps1:Line 11」の場所で呼び出される場所を正しく記述します

1 Answer


2


使用するのはアサート_function_ではなく、「メンバー関数」として使用されるアサート_script block_です。 しかし、それはまだスクリプトブロックです。

この報告された問題によると:https://connect.microsoft.com/PowerShell/feedback/details/531086/depending-on-how-you-invoke-a-script-block-the-invocation-details-may-not-スクリプトブロック内から利用可能#

スクリプトブロックからの `Get-PSCallStack`の呼び出しに何か問題があります。 したがって、あなたの質問への答えはおそらく次のとおりです。はい、それはPowerShellの問題です。

さて、関数を使用することをお勧めします。 スクリプトをリファクタリングして関数(ダーティバージョン、悪名など)を使用すると、期待どおりに機能します。

#File 1 (Tester.ps1)
#Creates the tester object

function AssertTrue {
    param($expression);

    $stackFrame = (Get-PSCallStack)[1]

    try{
        $result = . $expression;
        if($result -eq $true){
            LogPass
        }else{
            LogFailure ("Evaluation Failed expected ""$true"" got ""$false""") $stackFrame
        }
    }catch [Exception]{
        LogFailure "Unexpected exception encountered" $stackFrame
    }
}

function LogPass {
    #Do nothing
}

function LogFailure {
    param($message, $stackFrame);
    "Failure Encounterd";
    "Command: $($stackFrame.Command)"
    "Location: $($stackFrame.Location)";
    "Message: $message";
}

And

#File 2 (TestCase.ps1)
#Runs the tests using the tester object

. (Resolve-Path "Tester.ps1");

function TestFailure {
    $expression = {$false};
    AssertTrue $expression
}

TestFailure