mcpField
M
migrate-nunit-to-mstest

migrate-nunit-to-mstest

github.com/dotnetテスト・品質5.8k1.8k 回インストール1 日前に更新
リポジトリ

migrate-nunit-to-mstest について

NUnit 3 または 4 のテストプロジェクトを、ターゲットフレームワークとテストランナーを維持して MSTest v4 に移行するスキルです。調査、意味の対応付け、移行、検証を案内します。

主な機能

  1. 01NUnit のバージョンとテストランナーの検出
  2. 02パッケージ置換とテスト変換の案内
  3. 03ライフサイクルとアサーションの意味対応
  4. 04データ、フィルター、並行動作の維持
  5. 05ビルドとテストの検証手順

活用シーン

  1. 01NUnit 3 または 4 のプロジェクト移行
  2. 02NUnit から MSTest への個別のコンパイル問題の解決
  3. 03変換前の高リスクなテスト動作の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dotnet/skills --skill migrate-nunit-to-mstest

インストール後、Claude Code で/migrate-nunit-to-mstestを入力して読み込まれたか確認します。

同梱ファイルreferences/mapping-cheatsheet.md

詳細

NUnit から MSTest への移行

ターゲットフレームワークやテストプラットフォームを変更せずに、NUnit 3 または 4 のテストを MSTest v4 に変換します。移行が成功するとビルドが通り、同じテストケースが検出され、成功/失敗、ライフサイクル、データ、フィルタリング、並行処理のセマンティクスが維持されます。

対象範囲

プロジェクトに NUnit パッケージまたはソースが含まれており、ユーザーが MSTest を希望している場合に限り、このスキルを使用してください。プロジェクトがすでに MSTest を使用していて NUnit のテストが含まれていない場合は、フレームワークの移行は不要であると伝え、変更を加えないでください。

このフレームワーク変換を、ターゲットフレームワークのアップグレードや VSTest/MTP の移行と組み合わせないでください。別の移行を始める前に、1 つの移行を完了し、検証してください。

ワークスペースの契約

  • 現在の作業ディレクトリ内でプロジェクトとソースを検索してください。このスキルのディレクトリ配下でユーザーファイルを探してはいけません。
  • 成果物の種類を判定してください。「このプロジェクトを変換して」は編集、ビルド、テストを行い、「計画を提示して」は編集せずに回答します。
  • ユーザーが指定したプロジェクトの範囲を維持してください。共有 props は、その範囲の NUnit パッケージまたはランナーの設定を管理している場合に限り、変更できます。
  • 最終回答には、移行元の NUnit のバージョン、維持したランナー、変更したファイル、リスクの高いセマンティクスのマッピング、実際のテスト件数を記載してください。

応答モード

  • 移行全体の依頼: 調査、編集、ビルド、テストを行ってください。計画だけで終わらせないでください。
  • コンパイルエラーまたは API に関する限定的な質問: 関連するマッピングだけを適用してください。
  • 未対応のターゲットフレームワーク: パッケージを変更する前に停止してください。MSTest v4 をテストアプリケーションで使用するには、.NET 8 以降、または .NET Framework 4.6.2 以降が必要です。別途承認された TFM アップグレードまたは MSTest v3 を提案してください。

結果に影響する判断

検出された状態必須の対応
NUnit のパッケージ、名前空間、属性、制約が残っていない停止し、変更を加えず、既存のテストコマンドを 1 回実行して、すでに MSTest を使用しているプロジェクトが正常であることを確認します。
ソースが VSTest を使用しているVSTest を維持します。リポジトリで明示的な Microsoft.NET.Test.Sdk のバージョン指定を管理している場合は、それを維持して更新し、MTP のプロパティは導入しないでください。
ソースが MTP を使用しているNUnit 固有の MTP 設定を MSTest MTP の設定に置き換えます。MSTest.Sdk を優先し、メタパッケージを使う場合は EnableMSTestRunner=true と OutputType=Exe を設定します。
NUnit が既定のフィクスチャのライフサイクルを使用しているNUnit は通常、すべてのテストケースで 1 つのフィクスチャインスタンスを共有しますが、MSTest はテストごとに新しいクラスインスタンスを作成します。クラス間で共有し続ける必要がある状態は、[ClassInitialize] で初期化する静的フィールドに移すか、その状態がテストごとのものであることを確認したうえで、インスタンスフィールドのままにしてください。
NUnit に Parallelizable の設定がない直列実行を維持します。NUnit と MSTest はどちらも既定では直列実行であるため、[assembly: Parallelize] を追加しないでください。
NUnit が並列実行を明示的に有効にしている実効範囲とワーカー数を変換してください。フィクスチャレベルの設定からメソッドレベルの並列実行を推測してはいけません。

詳細なマッピングについては、プロジェクトに含まれる構成を references/mapping-cheatsheet.md で検索し、該当するセクションだけを読んでください。

迅速な手順

一般的な移行は、4 つのフェーズで進めます。1 回のまとめての調査、1 回の編集、1 回の dotnet test、簡潔な結果報告です。

  • 利用可能な場合は、既存の CI/テスト結果をベースラインとして使用してください。
  • 件数が不明で、プロジェクトにパラメーター化テスト、フィクスチャの状態、名前空間のセットアップ、リトライ、カスタム属性、または明示的な並列化が含まれる場合は、編集前にベースラインを実行してください。
  • dotnet test で十分な場合は、restore、build、test を別々のコマンドで実行しないでください。
  • 動作のマッピングが完了するまで、NUnit ランナーの設定を削除しないでください。

ワークフロー

1. ベースラインを確立する
  1. テストプロジェクト、中央パッケージファイル、global.json、.runsettings、testconfig.json、NUnit の構成を一括で読み取ります。
  2. NUnit、NUnit3TestAdapter、NUnit.Analyzers、NUnit.Framework、NUnit.Framework.Legacy、using NUnit.Framework から NUnit の使用を検出します。
  3. 解決されたパッケージバージョンを基に、ソースが NUnit 3 と NUnit 4 のどちらかを明記します。
  4. VSTest または MTP を検出し、そのまま維持します。判別が難しい場合にのみ platform-detection を使用します。
  5. ターゲットフレームワークを記録し、MSTest v4 がサポートしていない場合は作業を中止します。
  6. リスクの高い構成要素を洗い出します。
    • [TestFixture(...)]、[TestFixtureSource]、[FixtureLifeCycle]、パラメーター付きコンストラクター
    • [TestCase]、[TestCaseSource]、TestCaseData、[Values]、[Range]、[Random]、[Sequential]、[Pairwise]、カスタムデータ属性
    • [Theory]、[Datapoint]、[DatapointSource]、自動 bool/enum データポイント、Assume.That
    • [OneTimeSetUp]、[OneTimeTearDown]、[SetUpFixture]、継承ベースのセットアップ
    • Assert.That、Assert.Multiple、Assert.Throws、Assert.Catch、コレクション制約
    • [Parallelizable]、[NonParallelizable]、[LevelOfParallelism]、[Order]、[SingleThreaded]
    • [Apartment]、[RequiresThread]、[CancelAfter]、[Timeout]
    • [Culture]、[Platform]、[SetCulture]、[SetUICulture]
    • [Explicit]、[Repeat]、[Retry]、[MaxTime]、カテゴリ、プロパティ、[TestOf]
    • [DefaultFloatingPointTolerance]、[NonTestAssembly]、非推奨のフィクスチャライフサイクルの別名
2. ランナーを切り替えずにパッケージを置き換える

置き換え対象となる NUnit 固有のパッケージ(NUnit、NUnit3TestAdapter、NUnit.Analyzers、NUnit コンソールランナーパッケージ、NUnit 固有の MTP アダプターなど)を削除します。

構成済みのパッケージソースから解決した、現行の安定版 MSTest v4 メタパッケージをデフォルトとして使用します。

<PackageReference Include="MSTest" Version="4.4.0" />

このバージョン固定は現行リリースを例示したものです。実際の移行時には、現行の安定版を解決して固定してください。ソースプロジェクトが VSTest 用の Microsoft.NET.Test.Sdk 依存関係を明示的に持っている場合は、そのまま維持します。MTP を維持する場合は、MSTest.Sdk を優先します。それ以外の場合は、EnableMSTestRunner=true と OutputType=Exe を使用します。

TargetFramework は変更しないでください。該当する動作を移行してから、NUnit の .runsettings アダプター設定を削除します。

3. 機械的な変換を行う
NUnitMSTest
[TestFixture] またはテストを含むフィクスチャ[TestClass]
[Test][TestMethod]
[TestCase(...)][TestMethod] + [DataRow(...)]
[TestCaseSource(nameof(Cases))][TestMethod] + [DynamicData(nameof(Cases))]
[SetUp] / [TearDown][TestInitialize] / [TestCleanup]
[OneTimeSetUp] / [OneTimeTearDown]static [ClassInitialize] / [ClassCleanup]
[Category(value)][TestCategory(value)]
[Property(key, value)][TestProperty(key, value)]
[Ignore("reason")][Ignore("reason")] と [TestMethod]
[Timeout(ms)][Timeout(ms)] と [TestMethod]
[Retry(n)]n > 1 の場合は [Retry(n - 1)] と [TestMethod]、n = 1 の場合は削除

using NUnit.Framework; と using NUnit.Framework.Legacy; を削除します。メタパッケージを使用する場合は、using Microsoft.VisualStudio.TestTools.UnitTesting; を追加します。MSTest.Sdk では暗黙的なグローバル using が提供されます。

クラスを機械的に sealed にしたり、継承されたセットアップメソッドをまとめたりしないでください。

4. セマンティックマッピングを解決する

手順 1 で見つかったリスクの高い構文ごとに、マッピングのチートシートを読み込みます。以下のルールは必須です。

  • NUnit の既定の LifeCycle.SingleInstance は、MSTest のテストごとのクラスインスタンスとは異なります。クラスで共有されるフィールドは明示的に維持してください。
  • [OneTimeSetUp] と [OneTimeTearDown] は、静的な MSTest メソッドに変換します。これらが使用するインスタンス状態は、単に static を追加するのではなく、静的なホルダーに移してください。
  • NUnit の Assert.Throws<T> と Throws.TypeOf<T> は例外型の完全一致を要求するため、Assert.ThrowsExactly<T> にマッピングします。NUnit の Assert.Catch<T> と Throws.InstanceOf<T> は派生型を許容するため、Assert.Throws<T> にマッピングします。
  • NUnit の Is.TypeOf<T> は Assert.IsExactInstanceOfType<T> に、Is.InstanceOf<T> は Assert.IsInstanceOfType<T> にマッピングします。
  • NUnit の等値制約は、シーケンスを要素ごとに比較します。MSTest 4.3 以降では Assert.AreSequenceEqual を使用し、それ以外ではリストを具体化したうえで CollectionAssert.AreEqual を使用してください。シーケンスに対して、参照ベースの Assert.AreEqual は決して使用しないでください。
  • TestCase(ExpectedResult=...) と TestCaseData.Returns(...) では、期待される結果をアサートするよう、対象のテストを書き換える必要があります。
  • 必要に応じて、DynamicData から TestDataRow<T> を返すことで、行ごとの名前、カテゴリ、無視設定を維持してください。NUnit の行プロパティに、TestDataRow<T> と直接対応するものはありません。カスタムデータソースを使用するか、メタデータについて明示的に判断する必要があります。
  • MSTest 4.4 の組み合わせ属性は、NUnit の [Combinatorial]、[Values]、[Range]、[Random] にマッピングできます。using Microsoft.VisualStudio.TestTools.UnitTesting.Combinatorial; を追加してください。コンストラクターのセマンティクスは異なるため、NUnit の範囲とランダム値の境界は明示的に変換してください。[Sequential] には、引き続き明示的な行またはカスタムデータソースが必要です。
  • NUnit の [Pairwise] に対応する MSTest 組み込み機能はありません。DynamicData に正確な生成済み行を維持するか、検証済みのペアワイズ ITestDataSource を使用してください。完全な直積の組み合わせでは、テスト件数と実行コストが変わります。
  • [Theory]、[Datapoint]、[DatapointSource] は、明示的な DynamicData または組み合わせソースに変換してください。bool/enum 値の自動生成と、すべての行が前提条件に違反した場合に Theory が失敗するルールを維持してください。
  • [Explicit]、[Repeat]、パラメーター化フィクスチャ、フィクスチャソース、Assert.Multiple には、動作が同一の機械的なマッピングはありません。意図的に書き換えるか、手作業での追加対応が必要であることを報告してください。暗黙のうちに近似してはなりません。
  • NUnit の [Retry(n)] は初回の試行を回数に含めますが、MSTest の [Retry(n)] は初回の試行後の再試行回数を数えます。1 を差し引き、NUnit の RetryExceptions フィルターは別途確認してください。
  • [CancelAfter(ms)] は [Timeout(ms, CooperativeCancellation = true)] にマッピングします。VSTest では、NUnit が挿入する CancellationToken パラメーターを削除し、挿入された TestContext.CancellationToken またはプロパティベースの TestContext.CancellationToken を使用してください。そうしないと、VSTest はそのパラメーターを不足データとして扱います。維持するランナーが挿入をサポートしていると確認できた場合に限り、メソッドのトークンを残してください。フィクスチャレベルの既定値は、該当するすべてのテストメソッドとライフサイクルメソッドに展開してください。
  • [Apartment(ApartmentState.STA)] は [STATestClass] または [STATestMethod] にマッピングします。非同期の継続処理を STA スレッド上に維持する必要がある場合は、UseSTASynchronizationContext = true を設定してください。MTA は MSTest の既定値です。[RequiresThread] と [SingleThreaded] はスレッドの同一性を保証しますが、MSTest の属性では通常それを維持できません。カスタムエグゼキューターを使用するか、手作業での追加対応が必要であることを報告してください。
  • NUnit のプラットフォームおよびカルチャーの条件は、OSCondition、ArchitectureCondition、または MemberCondition ヘルパーにマッピングします。SetCulture と SetUICulture は、元のカルチャーを保存して復元するセットアップ/クリーンアップにマッピングします。
  • [DefaultFloatingPointTolerance] は、影響を受けるすべてのアサーションで、明示的なデルタ値に展開してください。メソッド、フィクスチャ、アセンブリの順の優先順位を維持してください。
5. ライフサイクルと名前空間のセットアップを維持する
  • [SetUp] と [TearDown] は、テストごとのライフサイクルメソッドとして維持します。
  • NUnit の既定ではフィクスチャのインスタンスが 1 つだけ作成されるため、すべての可変インスタンスフィールドを確認してください。テスト間で共有する必要がある場合は、[ClassInitialize] で作成し、[ClassCleanup] で解放する静的状態を使用します。
  • [FixtureLifeCycle(LifeCycle.InstancePerTestCase)] は、MSTest のクラスのインスタンス化方法とすでに一致しています。この属性を削除し、テストごとのインスタンス状態を維持します。
  • NUnit の [SetUpFixture] は名前空間のスコープです。MSTest のアセンブリ初期化はアセンブリ全体が対象です。NUnit のセットアップがすでにアセンブリ全体を対象としている場合に限り、[AssemblyInitialize] を使用します。それ以外の場合は、スコープを広げずに、影響を受けるクラスまたは共有ヘルパーにセットアップを移します。
  • セットアップ/クリーンアップの継承順序を維持します。結果の順序が同等であると確認できない限り、基底メソッドと派生メソッドを統合しないでください。
  • NUnit の TestContext.WriteLine は、注入またはプロパティベースの MSTest TestContext.WriteLine に対応付けます。ディレクトリ、テスト名、添付ファイルの各 API は、個別に変換してください。
6. 並列実行と順序を維持する

NUnit と MSTest は、どちらも既定では直列に実行されます。並列実行が設定されていない NUnit プロジェクトに、並列実行を追加しないでください。

NUnit で明示的に並列実行が有効になっている場合:

  • アセンブリ [Parallelizable(ParallelScope.Fixtures)] -> [assembly: Parallelize(Workers = N, Scope = ExecutionScope.ClassLevel)]
  • フィクスチャの [Parallelizable(ParallelScope.Children)] またはメソッドレベルの並列実行 -> 共有インスタンス状態が安全であることを確認してから、メソッドレベルの MSTest 並列化を使用します
  • [NonParallelizable] -> 並列実行が有効な場合は [DoNotParallelize]
  • [LevelOfParallelism(N)] -> Workers = N
  • リソース単位のシリアル化には、[DoNotParallelize] より狭いロックを維持できる場合、MSTest 4.4 の [ResourceLock("key")] を使用できます

NUnit の [Order] は、一般的な依存関係の意味を表すものではありません。ソースが実際に前提条件を表している場合に限り、MSTest 4.4 の [DependsOn] を使用します。それ以外の場合は、テストを独立させて順序指定を削除するか、手動での後続対応として報告してください。

7. 同等性を検証する
  1. ベースラインで使用したものと同じプラットフォーム、フィルター、構成でテストを実行します。
  2. 検出数、成功数、失敗数、スキップ数を比較します。
  3. 相違点をすべて調査します。
    • 行の欠落 -> DataRow、DynamicData、組み合わせ、または行メタデータの変換
    • 例外/型の変化 -> 完全一致と派生型の対応付け
    • 状態に関する失敗 -> NUnit の単一インスタンスのフィクスチャセマンティクス、またはセットアップ順序
    • 並行性に関する失敗 -> Parallelize、DoNotParallelize、ワーカー数、またはリソースロック
    • スキップの変化 -> Ignore、Explicit、行レベルの無視、または再試行の動作
  4. 文書化された後続対応の対象でない限り、NUnit のパッケージ、名前空間、属性、制約、アダプター設定、カスタム NUnit 拡張機能が残っていないことを確認します。
  5. リスクの高い変更を含むファイルを読み返し、結果に正確な移行先 API を記載します。

最終応答は、次の形式にしてください。

  • 変更: ファイルと、リスクの高い変更の正確な対応付け。
  • 検証: 最終的なコマンドと、検出数/成功数/失敗数/スキップ数。
  • 維持: ターゲットフレームワーク、テストプラットフォーム、フィクスチャのスコープ、並行実行の方針。
  • 残件: 手動での後続対応、または「なし」。

完了条件

  • NUnit のバージョンとテストプラットフォームを特定した
  • NUnit のパッケージとソース内の構成要素を変換した
  • ターゲットフレームワークとテストプラットフォームを変更せずに維持した
  • 既定の単一インスタンスのフィクスチャセマンティクスを監査し、観測可能な動作を維持した
  • データ行のメタデータとアサーションのセマンティクスを維持した
  • 名前空間のセットアップと並列実行のスコープを、暗黙に広げていない
  • NUnit の公式属性一覧にあるすべての属性を、直接変換、書き換え、削除、または手動対応として分類した
  • ビルドが成功し、テスト結果がベースラインと一致した
  • サポートされていないカスタム拡張機能や動作を明記した

後続対応

ユーザーが MTP も希望している場合は、別途 migrate-vstest-to-mtp を実行します。同等性を確認した後に限り、writing-mstest-tests を使用してください。

コメント