test-tagging について
テストスイートを分析し、テストメソッドに標準タグを付けるスキルです。テスト分布やクリティカルパスのカバレッジを把握でき、指定に応じて監査またはソース編集を行います。
主な機能
- 01言語とテストフレームワークを特定
- 02固定分類に基づいてテストを分類
- 03既存タグの重複を回避
- 04タグの分布を集計
- 05監査またはソース編集に対応
活用シーン
- 01肯定・否定テストの構成を確認
- 02未分類のテストにタグを追加
- 03クリティカルパスのテストカバレッジを確認
- 04タグ分布レポートを作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dotnet/ skills --skill test-taggingインストール後、Claude Code で/test-taggingを入力して読み込まれたか確認します。
詳細
テストの特性タグ付け
サポートされている任意の言語の既存のテストスイートを分析し、各テストメソッドに標準化された特性タグを付けます。これにより、チームはテストの内訳(成功ケースと失敗ケース、クリティカルパスのカバレッジ、スモークテストなど)を把握できます。
言語別のガイダンス:呼び出し元から提供された、または実行時に一覧表示された
test-analysis-extensionsカタログと、対応する言語ファイルを読みます。 このヘルパーは参照専用であり、呼び出し可能なスキルではありません。存在しない場合は、 以下の組み込みフレームワーク表を使用し、制約を報告してください。
使用する場面
- テストプロジェクトを監査して、テストの種類の内訳を把握する
- タグの付いていないテストに特性属性を追加する
- テストスイート全体の特性の分布をまとめたレポートを生成する
- クリティカルパスに十分なカバレッジがあるか確認する
使用しない場面
- テストをゼロから作成する場合(任意の言語では
code-testingを、MSTest ではwriting-mstest-testsを使用) - テストの実行やフィルタリング(.NET では
run-testsを、他の環境では対応するネイティブランナーを使用) - テストフレームワーク間の移行
- 一般的な品質、コードの不適切なパターン、フレーキーテスト、アサーションの監査(
test-anti-patternsまたは対応する分析スキルを使用) - .NET の実行行数・分岐数・Cobertura の診断的な解釈や、プロジェクト全体の CRAP リスクの分析(
coverage-analysisを使用)。生のカバレッジデータの収集には、.NET ではrun-testsを、他の環境ではネイティブツールを使用 - 名前を指定したメソッド、クラス、またはファイルの CRAP 分析(
crap-scoreを使用) - テストが壊れた本番ロジックを見逃すような振る舞い上のギャップ(
test-gap-analysisを使用)
入力
| 入力 | 必須 | 説明 |
|---|---|---|
| テストプロジェクトまたはファイル | いいえ | テストプロジェクト、フォルダー、または特定のテストファイルへのパスです。省略された場合は、現在のワークスペースから検出します。 |
| 範囲 | いいえ | 動詞から推測します。tag/apply は編集、audit/classify/report はレポートのみ、both は両方が要求された場合にのみ適用します。曖昧な場合は、要求されていない編集を避けるため、audit を既定値とします。report-only と宣言されたフレームワークでは常にレポートを出力し、convention-based のフレームワークでは、ユーザーが規約を確認した後にのみ編集します。 |
| フレームワーク | いいえ | 自動検出されます。検出に失敗した場合は上書きできます。 |
特性の分類
これらの特性名と値を必ずそのまま使用してください。この表にない特性値を新たに作らないでください。
| 特性値 | 意味 | 判定基準 |
|---|---|---|
positive | 通常/有効な条件下で期待される動作を検証します | 成功、有効な出力、期待される状態、有効な入力で例外が発生しないことを検証します |
negative | 無効な入力、エラー、またはエッジケースが適切に処理されることを検証します | 例外、エラーコード、検証失敗、不正な入力の拒否を検証します |
boundary | 限界値、しきい値、空/null/None/nil の入力、最小値/最大値をテストします | 0、-1、int.MaxValue / sys.maxsize / Number.MAX_SAFE_INTEGER / math.MaxInt64 / i32::MAX、空文字列、null/None/nil/undefined、空のコレクション、有効範囲の境界値を扱います |
critical-path | 決して壊れてはならない中核ワークフローです。壊れるとユーザーの利用が妨げられます | 主要な公開 API またはユーザー向け機能の、主要な成功シナリオをテストします |
smoke | システムが稼働していることを素早く確認します | 複雑なセットアップが不要で、基本的な接続(例:サービスが解決される、エンドポイントが 200 を返す)を検証します |
regression | 過去に報告された特定のバグを再現します | バグ ID、issue 番号を参照するか、名前やコメントで修正内容を説明します |
integration | プロセス、ネットワーク、または永続化の境界をまたぎます | 実際のデータベース、HTTP クライアント、ファイルシステム、外部サービス、または複数コンポーネントのセットアップを使用します |
end-to-end | アプリケーションスタック全体にわたる完全なユーザーワークフローです | エントリーポイントから最終結果までの完全なシナリオを実行します。単一境界の integration とは異なります |
performance | 実行時間、スループット、またはリソース消費を検証します | 経過時間、メモリ、割り当てを検証するか、ベンチマークハーネス(BenchmarkDotNet、pytest-benchmark、benchmark.js、JMH、go test -bench、criterion.rs、XCTMetric、kotlinx-benchmark、Google Benchmark)を使用します |
security | 認証、認可、入力のサニタイズ、またはシークレットの取り扱いを検証します | SQL インジェクション、XSS、CSRF、不正アクセス、トークン検証、権限チェックをテストします |
concurrency | スレッドセーフ性、並列処理、または非同期処理の正しさを検証します | Task.WhenAll / Parallel.ForEach / SemaphoreSlim(.NET)、asyncio.gather / threading.Lock / multiprocessing(Python)、Promise.all / ワーカースレッド(JS/TS)、CompletableFuture / ExecutorService / synchronized(Java)、go func / sync.WaitGroup / sync.Mutex / chan(Go)、Mutex / Thread.new(Ruby)、tokio::spawn / Arc<Mutex<_>> / crossbeam(Rust)、DispatchQueue / actor(Swift)、coroutineScope / Mutex(Kotlin)、Start-Job / RunspacePool(PowerShell)、std::thread / std::mutex(C++)を使用するか、競合状態を再現します |
resilience | リトライロジック、タイムアウト、サーキットブレーカー、またはグレースフルデグラデーションをテストします | 一時的な障害、ネットワーク切断、またはサービス停止時の動作を検証します(例:Polly、tenacity、p-retry、resilience4j、hystrix、opossum、retry-go) |
destructive | 元に戻すことが難しい共有状態または外部状態を変更します | レコードの削除、リソースの破棄、グローバル設定の変更などを行います。CI の分離判断に役立ちます |
configuration | 設定の読み込み、デフォルト値、環境に応じた動作を検証します | 設定キーの欠落、無効な値、環境変数へのフォールバック、オプションの検証をテストします |
flaky | 断続的に失敗することが知られています(テストの健全性を追跡するメタタグ) | チームが信頼性に問題があると把握しているテストに付与します。隔離や安定化の優先順位付けに使用します |
1 つのテストに複数の特性を付与できます(例:negative と boundary の両方)。最低限、すべてのテストに positive または negative のいずれかを付与してください。
ワークフロー
ステップ 1: 言語、フレームワーク、タグ付け機能を検出する
パスを尋ねる前に、現在のワークスペースから要求されたテストスコープを解決してください。スキルコンテキストの Base directory にはこれらの指示が含まれており、ユーザーのリポジトリではありません。リポジトリのファイルが利用できないと主張する前に、常に現在の作業ディレクトリを検査してください。プロンプトの相対パスが存在しない場合は、ワークスペースで指定されたプロジェクト/ファイルを検索し、正確な結果で再試行してください。検索が成功すれば、対象が存在することが証明されます。その後に通常のリーダーが同じパスが見つからないと報告した場合、その矛盾はユーザーにファイルを求めるのではなく、リーダーのパス正規化またはトランスポートの失敗として扱ってください。
シェルのテキストリーダー(Unix では sed/cat、PowerShell では Get-Content)は、リーダーの可用性、トランスポート、またはパス正規化の失敗が確認された場合にのみ使用し、かつ正規パスが現在のワークスペース内に留まっていることを検証した後にのみ使用してください。コンテンツ除外、権限/ポリシー、ワークスペース境界、または不明な読み取り失敗の場合は停止してください。ワークスペース検索で読み取り可能な対象が見つかった後に、ユーザーにパスやファイルの内容を求めてはいけません。
auto-edit フレームワークの場合、パッチ/エディター呼び出しの失敗は、その失敗がツールの可用性、トランスポート、またはパス正規化であると確認された場合にのみ、停止条件にはなりません。古いコンテキスト、同時変更、権限/ポリシー、またはパス境界のエラーを回避してはいけません。シェルへのフォールバックの前に、現在のワークスペース内で正規パスを解決し、ファイルを新たに読み取り、期待される古いテキストと正確な一致数が変わっていない限り中止するアンカー付き変換を使用してください。その後、ファイル全体を再度開き、差分を検査し、ステップ 6 の検証を実行してください。ユーザーが適用を求めた場合、提案された属性を完了として報告してはいけません。
言語とフレームワークを特定してください。必要に応じて一致するバンドルされたリファレンスを読んでください。ファイル名には提供されたカタログを使用し、既知のディレクトリのみを確認してください。存在しない場合は、以下の組み込みルールから機能を分類してください:
auto-edit— フレームワークに、このスキルが安全に挿入できる正規のタグ構文がある(.NET[TestCategory]/[Trait]/[Category]/[Property]、pytest@pytest.mark.<name>、JUnit 5@Tag("...")、TestNGgroups = {"..."}、RSpec メタデータit "..." , :tag => true、Pester-Tag '...'、Kotest@Tags(...)、Swift Testing@Tag(.tagName)、Catch2[tag]、doctest* doctest::test_suite("tag")デコレーター)。report-only— フレームワークに正規の合意されたタグ属性がない。タグは Markdown テーブルでのみ報告し、ソースを編集しない(ビルドタグ規約のない Go 標準testing、一貫した describe プレフィックス規約のない Jest/Vitest、プロジェクト固有の cfg 規約のない Rust、テストプランのない XCTest、テスト名プレフィックス規約のない GoogleTest、describe プレフィックス規約のない Mocha)。convention-based— フレームワークがタグ付けに命名またはファイル規約を使用する(Go//go:build integrationビルドタグ、*_integration_test.goのようなファイル名サフィックス、GoogleTestINTEGRATION_*フィルタープレフィックス)。ユーザーがプロジェクト規約を確認した場合にのみ正規の編集を出力し、それ以外の場合はreport-onlyとして扱う。
ステップ 4 の前に機能をキャプチャしてください。
また、分類の前に要求されたモードをロックしてください。正規の属性が利用可能であるという理由で監査をソース編集に変えてはいけません。明示的なタグ付け/適用の要求がある場合にのみ編集してください。
ステップ 2:既存の特性を確認する
すでに特性属性が付与されているテストを確認します。拡張機能が読み込まれている場合はそれを使用し、そうでない場合は以下の組み込みテーブルを信頼できる情報源として使用してください。
| フレームワーク | 既存の属性 | 例 |
|---|---|---|
| MSTest | [TestCategory("...")] | [TestCategory("positive")] |
| xUnit | [Trait("Category", "...")] | [Trait("Category", "positive")] |
| NUnit | [Category("...")] | [Category("positive")] |
| TUnit | [Property("Category", "...")] | [Property("Category", "positive")] |
| JUnit 5 | @Tag("...") | @Tag("positive") |
| TestNG | @Test(groups = {"..."}) | @Test(groups = {"positive"}) |
| pytest | @pytest.mark.<name> | @pytest.mark.positive |
| RSpec | it の後にメタデータを記述 | it "...", :positive do |
| Pester | -Tag '...' | It '...' -Tag 'positive' |
| Kotest | @Tags(...) | @Tags(Positive) |
| Swift Testing | @Tag(.<name>) | @Test(.tags(.positive)) |
| Catch2 | 名前に [tag] を記述 | TEST_CASE("...", "[positive]") |
| doctest | * doctest::test_suite("...") デコレーター | TEST_CASE("..." *doctest::test_suite("positive")) |
重複を避けるため、すでにタグが付いているテストを記録してください。
ステップ 3:各テストメソッドを分類する
発見した各テストを一度だけ含む、正規のインベントリを作成します。 そのインベントリにテスト識別子、動作上の分類、特性を記録し、ソースの編集、テストごとの報告、合計、分布数には同じ行を使用します。分母を別途手作業で数えないでください。公開前に、報告した合計がインベントリの行数と一致することを照合し、各行が表示されているすべての特性数に反映されていることを確認します。
特性がない各テストメソッドについて、次の点を分析します。
- メソッド名 --
Invalid、Fail、Error、Throw、Reject、BadInput、Null、None、Nil、Negative、raises_、_throws_、_returns_errorを含む名前は、negativeを示唆します - アサーションの種類 --
Assert.ThrowsException/Assert.Throws/Should().Throw()/pytest.raises/expect(fn).toThrow/assertThrows/assert.Error(t, err)/expect { ... }.to raise_error/#[should_panic]/XCTAssertThrowsError/Should -Throw/EXPECT_THROWは、negativeを示唆します - 入力値 --
null/None/nil/undefined、""、0、-1、int.MaxValue/sys.maxsize/Number.MAX_SAFE_INTEGER/math.MaxInt64/i32::MAX、空のコレクションは、boundaryを示唆します - セットアップの複雑さ -- 基本的なアサーションのみの最小限のセットアップは
smokeを示唆します。外部依存関係(ファイル/データベース/ネットワーク/環境変数)はintegrationを示唆します - コメントと名前 -- イシュー番号や「regression」/「bug」/「fix for #...」への言及は、
regressionを示唆します - 時間のアサーション --
Stopwatch、BenchmarkDotNet、経過時間の確認、pytest-benchmark のフィクスチャ、benchmark.js、JMH@Benchmark、go test -bench、criterion.rs、XCTMetric、Google Benchmark、kotlinx-benchmark は、performanceを示唆します - 機能の中心性 -- 主要なパブリック API のエントリーポイントや重要なユーザーワークフローを対象とするテストは、
critical-pathを示唆します - セキュリティパターン -- 認証の検証、権限の確認、入力のサニタイズ、インジェクションのテスト、トークン/シークレットの処理は、
securityを示唆します - 並列/非同期構造 -- 言語ごとの並行処理プリミティブ(Trait Taxonomy の表を参照)は、
concurrencyを示唆します - 障害の注入 -- 障害のシミュレーション、リトライ、タイムアウト、サーキットブレーカーのテストは、
resilienceを示唆します - 状態の変更 -- 外部レコードの削除、リソースの破棄、共有/グローバル状態の変更は、
destructiveを示唆します - フルスタックのフロー -- エントリーポイントからデータ層を経て最終応答までを網羅し、完全なユーザーシナリオを扱うテストは、
end-to-endを示唆します - 構成/設定 -- 構成の読み込み、キーの欠落のテスト、オプションの検証、環境変数の確認は、
configurationを示唆します - 既知の不安定さ -- フレーキーテストに関するコメント付きの skip/ignore アノテーションがあるテスト、または名前に「flaky」/「intermittent」が含まれるテストは、
flakyを示唆します - デフォルト -- テストが通常の成功パスを検証する場合は、
positiveを付与します
positive と negative のどちらか判断に迷う場合は、アサーションを確認してください。成功をアサートしている場合は positive、失敗をアサートしている場合は negative です。
分布またはカバレッジの形状を監査するよう依頼された場合は、要約する前に、利用可能な本番コードを使って各テストが検証する正確な結果を特定します。境界値カバレッジの重複と、テストインベントリが名前付きしきい値の両側、およびビジネス上重要なパスにおける観測可能なコラボレーターの結果を網羅しているかを指摘します。これらは簡潔な分布に関する所見として扱い、新たな特性値にはしないでください。変更の推論を行わず、新しいテストを推奨せず、test-gap-analysis が担当する動作上のギャップ監査に踏み込まないでください。
ステップ 4:トレイト属性を適用する(またはレポートのみを出力する)
機能を適用する前に、モードを確定します。
- 監査モード(
audit、classify、report、または意図が曖昧な場合):機能にかかわらず、ソースを変更せずにテストごとの対応表と概要を出力します。 - 編集モード(
tag、apply、または明示的に要求されたboth):以下の機能ごとの分岐に進みます。
編集モードで、確定した機能が auto-edit の場合、各テストメソッドに適切な属性を追加します。トレイト属性は既存のテスト属性に隣接して配置します。例:
トレイトは、個々のテストメソッド/ケースのレベルで適用します。メソッド単位の分類をクラスレベルの単一カテゴリで代用しないでください。通常、メソッドごとに検証するのは、異なる正常系、異常系、境界の動作です。
MSTest:
[TestMethod]
[TestCategory("negative")]
[TestCategory("boundary")]
public void Parse_NullInput_ThrowsArgumentNullException() { ... }
xUnit:
[Fact]
[Trait("Category", "positive")]
[Trait("Category", "critical-path")]
public void CreateOrder_ValidItems_ReturnsConfirmation() { ... }
NUnit:
[Test]
[Category("regression")]
[Category("negative")]
public void Calculate_OverflowInput_ReturnsError() // Fix for #1234
{ ... }
pytest:
@pytest.mark.negative
@pytest.mark.boundary
def test_parse_none_input_raises_value_error():
...
JUnit 5:
@Test
@Tag("positive")
@Tag("critical-path")
void createOrder_validItems_returnsConfirmation() { ... }
TestNG:
@Test(groups = {"negative", "boundary"})
public void parse_nullInput_throwsIllegalArgumentException() { ... }
RSpec:
it "rejects null input", :negative, :boundary do
...
end
Pester:
It 'Rejects null input' -Tag 'negative','boundary' {
...
}
Kotest:
@Tags(Negative, Boundary)
class ParserSpec : StringSpec({
"rejects null input" { ... }
})
Swift Testing:
@Test(.tags(.negative, .boundary))
func parseNullInputThrows() throws { ... }
Catch2:
TEST_CASE("Parse null input throws", "[negative][boundary]") { ... }
どのモードでも、確定した機能が report-only の場合(Go 標準の testing、規約のない通常の Jest/Vitest、プロジェクト固有の cfg がない Rust、通常の XCTest、通常の GoogleTest、通常の Mocha)、ソースファイルを変更してはいけません。代わりに、各テストに推奨タグを対応付けた簡潔な一覧を出力します。ユーザーがタグの永続化やフィルタリング方法を尋ねた場合に限り、プロジェクト全体の規約を推奨します。分析のみの依頼では、レポートを出力して終了します。
編集モードで、確定した機能が convention-based の場合(例:Go の //go:build integration、*_integration_test.go、GoogleTest の INTEGRATION_* プレフィックス)、プロジェクトの規約をユーザーが確認している場合に限り、正規の編集を出力します。確認がない場合は report-only として扱います。
ステップ 5:トレイトの概要を作成する
タグ付けの後、概要表を作成します。ユーザーが分類の全項目を求めた場合を除き、件数がゼロではないトレイトだけを含めます。ゼロ件の行は、テストスイートの実際の構成を分かりにくくします。レポートのみを出力する小規模なテストスイートでは、テストごとの対応表とゼロ件ではない分布をまとめて示し、ダッシュボードに展開しないでください。
## Trait Distribution
| Trait | Count | % of Total |
|---------------|-------|------------|
| positive | 50 | 64.1% |
| negative | 28 | 35.9% |
| boundary | 8 | 10.3% |
| critical-path | 12 | 15.4% |
| **Total tests** | **78** | -- |
Note: Percentages exceed 100% because tests can have multiple traits.
次のような所見を含めます。
- 正常系テストと異常系テストの比率
- 主要な公開 API に対するクリティカルパステストがあるかどうか
- 確信を持って分類できなかったテスト(手動レビュー用に列挙)
boundary とその他の特殊なトレイトは追加で適用します。境界値での成功ケースも positive として数え、境界値で拒否されるケースも negative として数えます。このルールを適用した後に、正常系/異常系の分布を算出します。
ステップ 6:報告前に編集を検証する
auto-edit 対応の各フレームワークで、編集した属性をコンパイルし、テストが検出されることを確認するための、最も範囲を絞ったコマンドを実行します。ユーザーがタグの追加のみを求めた場合でも、これは必須です。構文上もっともらしい属性を追加しただけでは、編集は完了していません。
| フレームワーク | 最低限の検証 |
|---|---|
| .NET | dotnet build <test-project> を実行し、続けて dotnet test <test-project> --list-tests --no-build で検出を確認します。ユーザーから要求されない限り、テストスイートを実行しないでください。実行は run-tests に回します。 |
| pytest | リポジトリで設定されている pytest コマンドを使って、編集したテストスイートを収集します。 |
| JUnit/TestNG | リポジトリの Maven/Gradle テストタスクを使ってテストをコンパイルします。 |
| その他の auto-edit 対応フレームワーク | リポジトリで最も範囲を絞ったコンパイルまたはテスト検出コマンドを使用します。 |
編集またはパッチの適用に確実性がなかった場合は、検証前に編集後のファイル全体を再度開き、一覧の各行を、該当するテストの隣にある実際の属性と照合します。差分の一部や意図したパッチだけを根拠に成功を報告してはいけません。検証に失敗した場合は、正確なコマンドとエラーを報告します。コンパイルされていない編集について、分布が正常に引き継がれたと報告してはいけません。
検証
- すべてのテストメソッドに、少なくとも1つの特性分類(最低限
positiveまたはnegative)があること。report-onlyフレームワークではレポートに、auto-editフレームワークでは属性として付与します - 合計がテストごとの一覧の件数と一致し、表示された特性の件数がその一覧から算出されていること
- 分類表にない特性値を作り出していないこと
- 既存の特性属性を保持し、重複させていないこと
- 特性の概要テーブルが生成されていること
-
auto-editフレームワークでは、要求されていないテストを実行せずにプロジェクトがビルドでき、テストを検出できること(dotnet buildと一覧表示モード/pytest --collect-only/mvn test-compile/go vet ./.../cargo check --tests/npm run test:list/同等のコマンド) - テスト検出コマンドを利用できる場合、最終的な概要に検証が成功したコマンドと検出されたテスト件数を記載すること
-
report-onlyフレームワークでは、ソースファイルを変更していないこと -
convention-basedフレームワークでは、プロジェクトの規約が確認できた場合に限って編集を適用していること
よくある落とし穴
| 落とし穴 | 解決策 |
|---|---|
| テスト本体を読まずに特性を推測する | アサーションとセットアップを必ず読み、正確に分類してください |
テストに positive/negative を付けず、boundary だけを付ける | すべてのテストに positive または negative も付けてください。boundary は追加分類です |
| 検出したフレームワークに合わない属性構文を使う | 読み込まれた拡張機能または組み込みの一覧に合わせてください(xUnit に [TestCategory] を付けたり、unittest に @pytest.mark.x を付けたりしないでください) |
| 既存のカテゴリ属性を重複させる | 追加する前に、ステップ2で既存の特性を確認してください |
critical-path を過剰に付ける | すべてのヘルパーではなく、主要な公開エントリーポイントをテストする場合に限ってください |
| Go/標準の Jest/標準の Rust/標準の XCTest/標準の GoogleTest のソースを編集する | これらはデフォルトで report-only です。代わりに Markdown テーブルを出力してください。プロジェクト全体の規約(ビルドタグ、ファイル接尾辞、describe の接頭辞、テストプランのグループ化)をユーザーが確認した場合に限って編集してください |
| 規約ベースのフレームワークでタグの接頭辞を作り出す | 採用する前にプロジェクトの既存の規約を確認してください。_integration_test.go、//go:build integration、IntegrationTest の接頭辞のどれかを推測で選ばないでください |
| 言語固有の並行処理/非同期プリミティブを見落とす | 利用できる場合は読み込まれた拡張機能を使い、それ以外の場合は Trait Taxonomy の並行処理の行を参照してください |