失敗した.NET単体テストをPowerShellスクリプトまたは.NETから再実行する


8

Azure DevopsVisual Studio Testタスクには、非常に優れた機能があり、失敗した単体テストを再試行できます。これは、テスト時間が長く、不安定なテストがいくつかある場合に優れた機能です。Azure Devopsのこのテストタスクは、xUnit、NUnit、MSTestなどのさまざまなテストプラットフォームで機能します。(したがって、.NET用に書かれたテスト)

ここに画像の説明を入力してください

スクリプトから同じ動作を取得することは可能ですか?私はxUnitまたはNUnitを好み、PowerShellでスクリプトを実行します。

xUnitの場合-method "name"

指定されたテストメソッドを実行します(完全に指定することも、ワイルドカードを使用することもできます(例: 'MyNamespace.MyClass.MyTestMethod'または '* .MyTestMethod')。複数回指定した場合、OR操作として機能します。

NUnitには--where=EXPRESSION構文ソースがあります。

実行するテストを示す式。演算子==、!=、=〜および!〜を使用して実際の値と比較するテスト名、クラス、メソッド、カテゴリ、またはプロパティを指定できます。構文の詳細については、テスト選択言語を参照してください。

しかし、xUnitまたはNUnitの失敗したテストを収集してすべてを機能させる方法はわかりません。

もちろん、不安定なテストを修正する方が良いでしょうが、それは時々それほど簡単ではありません。

更新:から実行しています。NET / C#(PowerShellでトリガーされる可能性があります)も許容されます


PesterをPowerShellテストフレームワークとして使用できます。
Alex_P

これはPowerShellのテスト用ではないですか?ここではそうではなく、単体テストはC#/で記述されています。NET
ジュリアン

しかし、xUnitまたはNUnitの失敗したテストを収集してすべてを機能させる方法はわかりません。頭のてっぺん、カスタムITestLoggerWithParametersを使用して失敗したテスト名のリストを作成しますか?
ワイヒチ

したがってdotnet test --logger:custom、失敗したテスト名を収集します。
weichch

失敗したテストをPowerShellのみで実行しますか、それともPowerShellですべてのテストを実行してから、失敗したテストをPowerShellで再度実行してもよろしいですか?2つのテスト(1つは成功、1つは失敗)を含む最小限のコード例を提供できますか?
トーマス

回答:


0

PowerShellで正規表現を使用して結果を取得するには、少しの「手動作業」を行うことができます。

この例はXUnitを使用しています。したがって、実行する必要があるのdotnet test project.csprojは、変数の結果を格納することです。例は次のようになります

Test run for C:\Users\Tigrex\source\repos\ConsoleApp1\XUnitTestProject1\bin\Debug\netcoreapp2.2\XUnitTestProject1.dll(.NETCoreApp,Version=v2.2) Microsoft (R) Test Execution Command Line Tool Version 16.3.0 Copyright (c) Microsoft Corporation. All rights reserved. Starting test execution, please wait... A total of 1 test files matched the specified pattern. X XUnitTestProject1.UnitTest1.ThisIsAnotherFailedTestYesAgain [11ms] Error Message: Assert.Equal() Failure Expected: 2 Actual: 1 Stack Trace: at XUnitTestProject1.UnitTest1.ThisIsAnotherFailedTestYesAgain() in C:\Users\Tigrex\source\repos\ConsoleApp1\XUnitTestProject1\UnitTest1.cs:line 33 X XUnitTestProject1.UnitTest1.ThisIsAnotherFAiledTest [1ms] Error Message: Assert.Equal() Failure Expected: 2 Actual: 1 Stack Trace: at XUnitTestProject1.UnitTest1.ThisIsAnotherFAiledTest() in C:\Users\Tigrex\source\repos\ConsoleApp1\XUnitTestProject1\UnitTest1.cs:line 22 X XUnitTestProject1.UnitTest1.TestToFail [1ms] Error Message: Assert.Equal() Failure Expected: 2 Actual: 1 Stack Trace: at XUnitTestProject1.UnitTest1.TestToFail() in C:\Users\Tigrex\source\repos\ConsoleApp1\XUnitTestProject1\UnitTest1.cs:line 16 Total tests: 5 Passed: 2 Failed: 3 Total time: 1.2764 Seconds

あなたが見ることができるように、主にError Messageあなたがどこを探すべきかを知るヒントを与えるいくつかの一般的なパターンがあります、この場合、xUnitはエラーのものを示しますX testname [{time}ms] Error Message

そのテキストを正規表現と照合すると、希望する応答が得られます。私はこれを使用しました。X\s*(\S*)\s\[\d*ms\]\s*Error Message改善できると確信しています(私は正規表現の達人ではありません)が、その仕事をします。Error Messageたとえば削除できます。とにかく、続けます。

結果が一致したら、各結果のグループを取得するだけで済みTestNameます。この場合は、グループをに保存しました。そして、dotnet test ...

$result = dotnet test XUnitTestProject1/XUnitTestProject1.csproj 

$regex = 'X\s*(?<TestName>\S*)\s\[\d*ms\]\s*'

$matches = [regex]::Matches($result, $regex)
Foreach ($failedTest IN $matches)
{
    $failedTestName = $failedTest.Groups['TestName'].Value
   dotnet test --filter   "FullyQualifiedName=$failedTestName" 
}

このラインは$failedTestName = $failedTest.Groups['TestName'].Valueあなたが合格しようとした場合、必要である.Groups..FullyQualifiedName文字列、PowerShellは文字列リテラルとしてそれらを理解しています。

時間とパーセンテージを計算するには、同じことを行う必要があります。

また、最初の反復ではすべてのテストを一度に実行できるため簡単ですが、2回目以降は実行できません。必要なリスト(失敗したテストを維持するため)が必要です。

このようなものは仕事をします。

$times = 1

$result = dotnet test XUnitTestProject1/XUnitTestProject1.csproj 
$regexFailedtests = 'X\s*(?<TestName>\S*)\s\[\d*ms\]\s*'
$FailedTestMatches = [regex]::Matches($result, $regexFailedtests)

$totalTestExecutedRegex = 'Total tests:\s*(?<TotalTest>\d*)'
$totalTests = [regex]::Matches($result, $totalTestExecutedRegex)[0].Groups['TotalTest'].Value -as [int]

$totalTesPassedRegex = 'Passed:\s*(?<Passed>\d*)'
$totalTestsPassed = [regex]::Matches($result, $totalTesPassedRegex)[0].Groups['Passed'].Value -as [int]


#convert the failed test into a list of string, so it can be looped.
$listFailedTest = New-Object Collections.Generic.List[string]
Foreach ($failedTest IN $FailedTestMatches)
{
    $failedTestName = $failedTest.Groups['TestName'].Value
    $listFailedTest.Add($failedTestName)
}

$percentage = ($totalTestsPassed*100)/$totalTests #Calculate the percentage

while($times -lt 5 -and $percentage -lt 70) {#5 loops or > 70% of test working

    $listFailedTestInsideDo = New-Object Collections.Generic.List[string]
    $listFailedTestInsideDo = $listFailedTest;  #do a copy of the main list
    $listFailedTest = New-Object Collections.Generic.List[string] ##empty the main list.
    Foreach ($failedTestName IN $listFailedTestInsideDo)
    {

       $result2 = dotnet test --filter   "FullyQualifiedName=$failedTestName" 

       if($result2 -match'Passed:\s*\d*') #if contains passed then it worked
       {
            totalTestsPassed++

        }else{
        $listFailedTest.Add($failedTestName) #add in new List for the new loop
       }
    }

    $percentage = ($totalTestsPassed*100)/$totalTests

    $times++
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.