MSTest 4.4では、テストプロジェクトを、アプリケーションが本番環境で採用する可能性のあるものと同じデプロイモデルで実行できます。テストソースを生成し、Native AOTとトリミングを有効にします。この考え方は、通常のマネージドテスト実行を置き換えることを目的とするものではなく、アプリケーションの出荷前に、事前コンパイルや未使用コードの削除に関連する問題を明らかにするネイティブ経路を追加するものです。
Principal Software EngineerのAmaury Levéによると、MSTest.Sdk/4.4.0を使用し、net10.0をターゲットにしてPublishAot=trueを設定すると、MSTestのソース生成とネイティブ実行可能ファイルの経路が有効になります。MSTest.Sdkは、既定でMicrosoft Testing Platform、つまりMTPを使用します。一方、現在もVSTestを使用しているプロジェクトは、MTPへの移行ガイダンスを確認する必要があります。コマンドライン引数、CI統合、そしてサポートされる.runsettingsの一部の項目が異なるためです。
実際には何が変わるのか?
プロジェクトを設定した後、アプリケーションが対象とするものと同じオペレーティングシステムおよびアーキテクチャ向けにテストを発行する必要があります。ソースではlinux-x64識別子を使用した例が示されており、win-x64やosx-arm64などの値に置き換えることもできます。発行後は、生成された実行可能ファイルを直接実行するか、Windowsでは.exe拡張子を使用して実行します。
この経路では、Assembly.GetTypes()の呼び出しなど、アセンブリ全体に対する包括的なリフレクション検査への依存が減ります。また、生成された属性とデリゲートを使用して、サポートされるテストを生成し、呼び出します。ただし、ソース生成によってReflectionがなくなるわけではありません。既定のReflectionFreeモードでは、一部のリフレクションによるフォールバック経路が維持されます。互換性問題を調査する場合は、MSTestSourceGenMode=Rootingを使用して、検出されたテストメンバーを保持しながらリフレクションによる実行を継続できます。
拡大前の限定的なCI経路
実際的な推奨事項は、日々のフィードバックのために高速なマネージドテスト実行を維持し、そのうえでデプロイ経路に直接関係するテストプロジェクトを1つ選び、CIにNative AOTの試行を追加することです。2つの経路について、次の3つの明確な観点を比較する必要があります。
- まったく同じ数のテストが検出されること。
- テストについて同じ結果が得られること。
- 発行およびネイティブ実行の時間を、テスト実行時間とは分けて記録すること。
まずはスケジュールされたジョブ、またはリリース検証段階で試行を開始し、その試行が追加の発行・実行コストに見合うだけのシグナルを提供する場合に限り、すべてのマージリクエストへ移行するのが望ましいです。また、シリアライズ、依存性注入、設定のバインディング、Reflectionに依存するプラグイン、あるいはNative AOTとの互換性を証明する必要があるライブラリなど、デプロイに敏感な経路をテストするプロジェクトを選ぶべきです。単純な計算テストだけを含むプロジェクトでは、アプリケーションの実際の準備状況について大きな証拠は得られません。
受け入れゲートに変えるべき制約
一部のテストだけが成功し、一部のクラスが記録されないままプロセスが成功終了する場合があります。例えば、テストクラスが[TestClass]属性を直接宣言せずに継承している場合、クラスがアクセス可能でない場合、ローカルクラス、静的クラス、公開されていないクラス、または抽象クラスである場合などです。ソースによると、診断MSTEST0069は、これらのケースのいずれかを検出するのに役立ちます。そのため、テスト数の一致は無視できる注意事項ではなく、リリース条件にすべきです。
その他の制約には、公開テストメソッド、またはref、out、inパラメーターを使用するメソッドがあります。さらに、[AssemblyFixtureProvider]による一部の静的フィクスチャパターンはサポートされません。また、MSTest SDKの一部の統合、MTP拡張機能、CIレポートはNative AOT経路では利用できません。一方、記事によればTRXとCode Coverageのサポートは引き続き利用できます。そのため、アナライザーの警告やビルド診断は、無視する警告ではなく、移行のゲートとして扱うべきです。
なぜこの方法が重要なのか?
マネージドテストとNative AOT経路は、異なる2つの問いに答えます。前者は開発サイクルを高速化し、後者はテスト自体がアプリケーションで使用するデプロイモデル内で動作できることを検証します。これは最終的な本番成果物を包括的にテストすることと同等ではありません。設定、オペレーティングシステム、アーキテクチャ、外部サービス、パッケージングは異なる可能性があるためです。しかし、テストとアプリケーションの間でトリミングおよび事前コンパイルのモデルが異なるという重要な変数を取り除くことができます。
性能向上は保証されておらず、主な根拠にすべきでもありません。ソース生成によって検出および起動にかかる時間が短縮される可能性はありますが、実行時間、プロセスの起動、発行、そして残存するReflectionが全体の所要時間を左右する可能性があります。ここでの編集上の読み方は、速度面の向上が限定的であっても、試行の基本的な価値はテストとデプロイの一致度を高めることにあるということです。また、この方法は後戻り可能です。経路のコストが追加される信頼性を上回る場合は、実行頻度を下げたり、選択するプロジェクトを変更したり、マネージドテストスイートを中断せずに試行を停止したりできます。