xUnit v3 移行後にテストエクスプローラーで Theory のテストが[!](未実行) になる

概要・現象の確認

xUnit v2 から v3 へ移行すると、Visual Studio のテストエクスプローラーで Theory のテストに[!](未実行) の項目が残ることがあります。原因と対処法をこの記事では紹介します。

原因はテスト検出時の設定 (preEnumerateTheories) と Visual Studio のテストキャッシュです。 xunit.runner.json で設定を戻し、キャッシュを削除すると解消します。

症状

テストエクスプローラーでテストを全件実行すると、緑 (成功) の項目と並んで、灰色の文字に[!]アイコンの項目が残ります。[!]は「未実行 (Not Run)」の印で、失敗ではありませんがテストがされていない状況です。

  • 同じテスト名が2つ並ぶ。例: 灰色の TestColumns と、緑の TestColumns(System.String,System.String,System.String)
  • テストエクスプローラーの件数が実際のテスト数より多い (例: 77 件のテストに対して 98 件と表示される)
  • dotnet test や実行ログでは 全件が実行・成功している (例: Total: 77, Failed: 0, Not Run: 0 といった表示になります。)


xUnit v3 移行後にテストエクスプローラーで Theory のテストが[!](未実行) になる:画像1

原因

xUnit v3 への移行でテストランナーが変わり、Theory の検出方法が変わったことが原因です。原因は次の2つです。

原因1: 新しいランナーでは Theory のデータ行が検出時に展開されない

xunit.v3 は Microsoft Testing Platform (MTP) に対応しており、.NET 10 SDK では global.json で MTP を有効にしないと dotnet test が通りません。 MTP では Visual Studio も xUnit v3 本体のランナーでテストを検出します。 Theory のデータ行を検出時に1件ずつ展開するかどうかは preEnumerateTheories で決まります。この設定には共通の既定値がなく、ランナーごとに既定値が違います。

原因2: 旧アダプターで検出した項目がキャッシュに残る

Visual Studio は検出したテストを .vs\<ソリューション名>\v18\TestStore に保存しています。移行前に VSTest 用アダプターで検出した項目は、MTP に切り替えた後も削除されずに残りました。

  • キャッシュには MTP の項目 (executor://testingplatform-bridge/v1) と旧アダプターの項目 (executor://xunit/VsTestRunner2) が混在していた
  • 現在の xunit.runner.visualstudio 4.0.1 の識別子は VsTestRunner3 なので、VsTestRunner2 の項目は今の構成からは作られない
  • MTP での実行結果は古い項目には付かないため、古い項目が[!]のまま一覧に残る

原因1 を設定で直しても、原因2 のキャッシュがある間は[!]が消えません。そのため、対処法1 と対処法2 の両方が必要です。

発生するケース

[!]が出るのは [Theory] のテストだけです。データを持たない [Fact] のテストは検出も実行も 1メソッド = 1件なので、影響を受けません。
次の条件が重なると発生します。

  • テストプロジェクトを xunit (v2) から xunit.v3 に変更した
  • MTP モードで動かしている (.NET 10 SDK で global.json に "runner": "Microsoft.Testing.Platform" を設定したなど)
  • [Theory] にデータ属性を付けたテストがある。[InlineData]、[MemberData]、[ClassData]、DataAttribute を継承した自作属性のどれでも発生する
  • 移行前に Visual Studio でテストを検出したことがある (要因2 のキャッシュ)

対処法1: xunit.runner.json を作成する

xunit.runner.json で preEnumerateTheories を true にすると、検出時にデータ行が1件ずつ展開され、v2 の頃と同じ表示になります。 xunit.runner.json は xUnit の正式な設定ファイルで、この項目も公式ドキュメントに載っています。


1. テストプロジェクトのフォルダーに xunit.runner.json を作成する

xunit.runner.json
{
  "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
  "preEnumerateTheories": true
}


2. .csproj に、このファイルを出力フォルダーへコピーする設定を追加する

<ItemGroup>
  <Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

3. リビルドし、検出結果を確認する

注意点
  • DataAttribute を継承した自作属性は、SupportsDiscoveryEnumeration() が true を返す必要がある。false だとこの設定を有効にしても展開されない
  • 展開するデータはシリアライズできる値 (文字列や数値など) である必要がある
  • この設定を使わずに、パッケージを xunit.v3.mtp-off に替えて従来の VSTest 方式に戻す方法もある (Visual Studio 用アダプターの既定値 true が使われる)

対処法2: Visual Studio のテストキャッシュを削除する

対処法1 の後も[!]が残る場合は、旧アダプターの項目がキャッシュに残っています。 TestStore フォルダーを削除すると解消します。中身はテスト一覧のキャッシュなので、消しても次回の検出で作り直されます。

  1. Visual Studio を閉じる (開いている間はキャッシュファイルがロックされていて削除できないです。)
  2. ソリューションフォルダーにある次のフォルダーを削除する (.vs は隠しフォルダー) <ソリューションフォルダー>\.vs\<ソリューション名>\v18\TestStore
  3. Visual Studio を開き直し、ソリューションをリビルドする
  4. テストエクスプローラーで全件実行し、件数が実際のテスト数 (今回は 77 件) になり[!]が消えたことを確認する


v18 は Visual Studio 2026 の場合です。Visual Studio 2022 では v17 です。.vs フォルダーごと削除しても構いませんが、開いていたファイルなどの状態もリセットされます。

動作確認

修正後、再度テストを実行します。[!]の表示が消え、テストがすべて実行された状態になります。

xUnit v3 移行後にテストエクスプローラーで Theory のテストが[!](未実行) になる:画像2

AuthorPortraitAlt
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
作成日: 2026-10-26