実際の実行例
Spectre.Console に対する実際の変更 1 件(コミット 01027ef)を、カバレッジマップからジョブサマリーまでたどります。このページの出力はすべてその実行からコピーしたもので、手で書いたものではありません。
変更内容
Rule ウィジェットの 1 行のリファクタリングです。動作は何も変わりませんが、コードの変更であるため、通常のパイプラインではすべてのターゲットフレームワークで 141 クラスの全 787 テストを実行することになります。
// src/Spectre.Console/Widgets/Rule.cs, GetLineWithoutTitle
var text = border.GetPart(BoxBorderPart.Top).Repeat(maxWidth);
+var style = Style ?? Spectre.Console.Style.Plain;
return
[
- new Segment(text, Style ?? Spectre.Console.Style.Plain),
+ new Segment(text, style),
Segment.LineBreak
];
実行
マップは main で td record によって記録されています。プルリクエストでは次のように実行します。
$ td test --base main -- -f net10.0td: 1 changed file(s), 1 affected test project(s).Tests to run: filtered src/Spectre.Console.Tests/Spectre.Console.Tests.csproj (14 of 141 test class(es) run or reference the changed code, 0.6 s of 3.0 s (80% saved))Recorded test time: 0.6 s of 3.4 s (83% saved).Passed! - Failed: 0, Passed: 156, Skipped: 0, Total: 156 - Spectre.Console.Tests.dll (net10.0)td summary: passed src/Spectre.Console.Tests/Spectre.Console.Tests.csproj (14 class(es), 4.6 s)1 project(s) run, 0 failed, 0 skipped.Recorded test time: 0.6 s of 3.4 s (83% saved).
141 クラスの 787 テストではなく、14 クラスの 156 テストが実行されました。Spectre.Console.Ansi.Tests プロジェクトはビルドすらされていません。依存しているものが何も変更されていないためです。
その 14 クラスは正しかったのか
確認のため、GetLineWithoutTitle が例外をスローするようにして、テストスイート全体を実行しました。失敗したのはちょうど 14 クラスで、それは TestDetta が選択した 14 クラスと一致しました。該当するのは AlignTests+Center、+Left、+Right、CanvasTests、ColumnsTests、ExceptionTests、LayoutTests、PadderTests、PanelTests、RecorderTests、RowsTests、RuleTests、TableTests、TextPathTests です。そのほとんどは Rule に一切言及していません。レイアウトやパネルを経由して到達しており、これはカバレッジマップでは把握できても、名前による検索では見つけられないものです。
ジョブサマリー
--summary-file "$GITHUB_STEP_SUMMARY" を指定すると(GitHub Action では自動的に設定されます)、すべてのプルリクエストに次のようなサマリーが付きます。何が実行されたか、各クラスが実行された理由、何がスキップされたかが示されます。
TestDetta test selection
1 changed file(s) compared with main.
- 1 of 1 affected test project(s) ran, 0 skipped.
- Recorded test time: 0.6 s of 3.4 s (83% saved).
- All selected tests passed.
src/Spectre.Console.Tests/Spectre.Console.Tests.csproj: passed, 14 test class(es), recorded time 0.6 s of 3.0 s (80% saved)- why:
14 of 141 test class(es) run or reference the changed code - classes:
AlignTests+Center:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)AlignTests+Left:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)AlignTests+Right:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)CanvasTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)ColumnsTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)ExceptionTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)LayoutTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)PadderTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)PanelTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)RecorderTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)RowsTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)RuleTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)TableTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)TextPathTests:ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)
- skipped: 127 class(es) that ran none of the changed code and name none of it
- why:
ここではクラス名を短縮しています。実際のサマリーには完全な名前(Spectre.Console.Tests.Unit.RuleTests)が出力されます。
理由を確認する
すべての判断には、読んで確認できる理由があります。-v を指定すると、その経緯が stderr に書き込まれます。
[DBG] CodeChangeDetector: src/Spectre.Console/Widgets/Rule.cs: Modified Spectre.Console.Rule GetLineWithoutTitle(RenderOptions,int)
[DBG] CodeChangeDetector: src/Spectre.Console/Widgets/Rule.cs: 1 changed symbol(s), affects whole project: False
[DBG] TestSelector: Spectre.Console.Rule GetLineWithoutTitle(RenderOptions,int) is affected because it changed
[DBG] TestSelector: Spectre.Console.Rule Render(RenderOptions,int) is affected because GetLineWithoutTitle
[DBG] TestSelector: Spectre.Console.Rule GetLineWithoutTitle(RenderOptions,int): test classes taken from coverage
また、--format json では、スクリプトやダッシュボード向けに、すべてのクラスの判断を根拠と推定時間とともに出力します。
{
"project": "src/Spectre.Console.Tests/Spectre.Console.Tests.csproj",
"mode": "Filtered",
"reason": "14 of 141 test class(es) run or reference the changed code",
"estimate": {
"fullSeconds": 3,
"selectedSeconds": 0.6,
"savedSeconds": 2.4
},
"decisions": [
{
"class": "Spectre.Console.Tests.Unit.AlignTests+Center",
"selected": true,
"kind": "coverage",
"evidence": "ran Spectre.Console.Rule.GetLineWithoutTitle(RenderOptions,int), which changed (map 01027efcd6c4)"
},
{
"class": "Spectre.Console.Tests.PublicApiTests",
"selected": false,
"kind": "skipped",
"evidence": "ran none of the changed code and names none of it (map 01027efcd6c4)"
},
"…139 more"
]
}
独自の方法でテストを実行する
td affected --format commands は TestDetta が行う dotnet test の呼び出しを出力するため、独自のスクリプトで実行できます。
dotnet test src/Spectre.Console.Tests/Spectre.Console.Tests.csproj --filter 'FullyQualifiedName~Spectre.Console.Tests.Unit.AlignTests+Center.|FullyQualifiedName~Spectre.Console.Tests.Unit.AlignTests+Left.|FullyQualifiedName~Spectre.Console.Tests.Unit.AlignTests+Right.|FullyQualifiedName~Spectre.Console.Tests.Unit.CanvasTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.ColumnsTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.ExceptionTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.LayoutTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.PadderTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.PanelTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.RecorderTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.RowsTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.RuleTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.TableTests.|FullyQualifiedName~Spectre.Console.Tests.Unit.TextPathTests.'
40 のリポジトリ全体での結果
1 つの変更は 1 つのデータポイントにすぎません。評価用コーパスでは、40 のオープンソースライブラリのメンバーを 1 つずつ変更しています。1 つのメンバーへの変更に対して TestDetta が実行したテストクラスの割合は中央値で 28% で、40 リポジトリのうち 18 リポジトリでは 4 分の 1 以下でした。ほぼすべてのテストがコアに触れるライブラリ(Scriban、Markdig)ではあまり効果がなく、レイヤー化されたコードで最も効果があります。失敗したクラスはすべて選択結果と照合しました。失敗した変更 2,941 件のうち見逃しは 3 件で、それぞれ修正済みです。