1

私は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);

Assert は 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" です。

4

1 に答える 1

2

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

この報告された問題によると: 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";
}

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

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

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

TestFailure
于 2010-08-24T15:48:42.470 に答える