次の方法で共有


Microsoft.Testing.Platform の拡張機能をビルドする

この記事では、テスト フレームワーク自体以外の Microsoft.Testing.Platform の機能拡張ポイントについて説明します。 テスト フレームワークの作成については、「 テスト フレームワークの構築」を参照してください。

完全な拡張ポイントの概要とプロセス内/プロセス外の概念については、「 カスタム拡張機能の作成」を参照してください。

機能拡張ポイント

テスト プラットフォームには、プラットフォームとテスト フレームワークの動作をカスタマイズできる追加の拡張ポイントが用意されています。 これらの拡張ポイントは省略可能であり、テスト エクスペリエンスを強化するために使用できます。

拡張

この API を拡張すると、カスタム拡張機能はテスト ホスト プロセスの内外の両方に存在することになります。

アーキテクチャ セクションで説明したように、最初の手順では、 を作成し、それを使用してテスト フレームワークと拡張機能を登録する必要があります。

var builder = await TestApplication.CreateBuilderAsync(args);

メソッドは、 という名前の文字列 () の配列を受け入れます。 これらの引数は、テスト プラットフォームのすべてのコンポーネント (組み込みコンポーネント、テスト フレームワーク、および拡張機能を含む) にコマンド ライン オプションを渡すために使用でき、それらの動作をカスタマイズすることが可能です。

通常、渡される引数は標準 メソッドで受け取った引数です。 ただし、ホスティング環境が異なる場合は、引数の一覧を指定できます。

引数には、必ずダブルハイフン--を付けなければなりません。 たとえば、 のようにします。

テスト フレームワークや拡張点などのコンポーネントでカスタム コマンド ライン オプションを提供する必要がある場合は、 インターフェイスを実装することでこれを行うことができます。 その後、この実装は、次に示すように プロパティの登録ファクトリを介して に登録できます。

builder.CommandLine.AddProvider(
    static () => new CustomCommandLineOptions());

提供されている例では、 は インターフェイスの実装です。このインターフェイスは、次のメンバーとデータ型で構成されます。

public interface ICommandLineOptionsProvider : IExtension
{
    IReadOnlyCollection<CommandLineOption> GetCommandLineOptions();

    Task<ValidationResult> ValidateOptionArgumentsAsync(
        CommandLineOption commandOption,
        string[] arguments);

    Task<ValidationResult> ValidateCommandLineOptionsAsync(
        ICommandLineOptions commandLineOptions);
}

public sealed class CommandLineOption
{
    public string Name { get; }
    public string Description { get; }
    public ArgumentArity Arity { get; }
    public bool IsHidden { get; }

    // ...
}

public interface ICommandLineOptions
{
    bool IsOptionSet(string optionName);

    bool TryGetOptionArgumentList(
        string optionName,
        out string[]? arguments);
}

以上のように、は インターフェイスを拡張します。 そのため、他の拡張機能と同様に、 API を使用してそれを有効または無効にすることができます。

の実行順序は次のとおりです。

"ICommandLineOptionsProvider" インターフェイスの実行順序を表す図。

APIとその平均を調べましょう。

: このメソッドは、コンポーネントで提供されるすべてのオプションを取得するために使用されます。 各 は、次のプロパティを指定する必要があります。

: これはオプションの名前で、ダッシュなしで表示されます。 たとえば、filter はユーザーにより として使用されます。

: これはオプションの説明です。 ユーザーがアプリケーション ビルダーに を引数として渡すと表示されます。

: オプションのアリティとは、そのオプションまたはコマンドが指定された場合に渡すことができる値の数を指します。 現在使用可能な機能は次のとおりです。

  • : 引数アリティが 0 であることを表します。
  • : 引数アリティが 0 または 1 であることを表します。
  • : 引数アリティが 0 以上であることを表します。
  • : 引数アリティが 1 つ以上であることを表します。
  • : 引数アリティが 1 つのみであることを表します。

例については、System.CommandLine アリティ テーブルを参照してください。

: このプロパティは、オプションは使用できるものの、 が呼び出されると説明には表示されないことを示します。

: このメソッドは、ユーザーによって提供される引数を検証するために使用されます。

たとえば、カスタム テスト フレームワークの並列処理の程度を表す、 という名前のパラメーターがある場合、ユーザーは を入力する可能性があります。 このシナリオでは、並列処理の程度は 以上が想定されるため、値 は無効になります。 を使用すると、事前検証を実行し、必要に応じてエラー メッセージを返すことができます。

上記のサンプルに対して可能な実装は、次のとおりです。

public Task<ValidationResult> ValidateOptionArgumentsAsync(
    CommandLineOption commandOption,
    string[] arguments)
{
    if (commandOption.Name == "dop")
    {
        if (!int.TryParse(arguments[0], out int dopValue) || dopValue <= 0)
        {
            return ValidationResult.InvalidTask("--dop must be a positive integer");
        }
    }

    return ValidationResult.ValidTask;
}

: このメソッドは最後のメソッドとして呼び出され、グローバルな一貫性チェックを実行できます。

たとえば、テスト フレームワークに、テスト結果レポートを生成してファイルに保存する機能があるとします。 この機能には オプションを使用してアクセスでき、ファイル名は で指定されます。 このシナリオでは、ユーザーがファイル名を指定せずに オプションのみを指定した場合、ファイル名なしでレポートを生成できないため、検証は失敗します。 上記のサンプルに対して可能な実装は、次のとおりです。

public Task<ValidationResult> ValidateCommandLineOptionsAsync(ICommandLineOptions commandLineOptions)
{
    bool generateReportEnabled = commandLineOptions.IsOptionSet(GenerateReportOption);
    bool reportFileName = commandLineOptions.TryGetOptionArgumentList(ReportFilenameOption, out string[]? _);

    return (generateReportEnabled || reportFileName) && !(generateReportEnabled && reportFileName)
        ? ValidationResult.InvalidTask("Both `--generatereport` and `--reportfilename` need to be provided simultaneously.")
        : ValidationResult.ValidTask;
}

メソッドは、プラットフォーム自体によって解析された引数情報をフェッチするために使用される サービスを提供することに注意してください。

拡張

は、テスト セッションの前後にコードを実行できるインプロセス拡張機能です。

カスタム を登録するには、次の API を利用します。

var builder = await TestApplication.CreateBuilderAsync(args);

// ...

builder.TestHost.AddTestSessionLifetimeHandle(
    static serviceProvider => new CustomTestSessionLifeTimeHandler());

ファクトリは IServiceProvider を利用して、テスト プラットフォームで提供されるサービス スイートへのアクセスを取得します。

Von Bedeutung

API は登録された順序で呼び出されるため、登録のシーケンスは重要です。

インターフェイスには、以下のメソッドが含まれます。

public interface ITestSessionLifetimeHandler : ITestHostExtension
{
    Task OnTestSessionStartingAsync(
        SessionUid sessionUid,
        CancellationToken cancellationToken);

    Task OnTestSessionFinishingAsync(
        SessionUid sessionUid,
        CancellationToken cancellationToken);
}

public readonly struct SessionUid(string value)
{
    public string Value { get; } = value;
}

public interface ITestHostExtension : IExtension
{
}

は、すべての拡張機能のベースとして機能する の型です。 他のすべての拡張点と同様に、IExtension からも継承されます。 そのため、他の拡張機能と同様に、 API を使用してそれを有効または無効にすることができます。

この API の詳細に注意を払いましょう。

: このメソッドは、テスト セッションの開始前に呼び出され、現在のテスト セッションに不透明な識別子を提供する オブジェクトを受け取ります。

: このメソッドは、テスト セッションの完了後に呼び出され、テスト フレームワークがすべてのテストの実行を完了しており、関連するすべてのデータをプラットフォームに報告していることを確認します。 通常、このメソッドでは、拡張機能はカスタム資産またはデータを共有プラットフォーム バスに送信するために を使用します。 このメソッドは、テスト セッションが終了したことをカスタムのアウトプロセス拡張機能に通知することもできます。

最後に、どちらの API も、拡張機能が受け入れる必要がある を取得します。

拡張機能が集中的な初期化を必要としており、ユーザーが async/await パターンを使用する必要がある場合には、 を参照できます。 拡張点の間で状態を共有する必要がある場合は、 セクションを参照できます。

拡張

は、何よりも先にコードを実行できるようにするインプロセス拡張機能であり、テスト ホストの架空メインの最初の行にアクセスできるようなものです。

カスタム を登録するには、次の API を利用します。

var builder = await TestApplication.CreateBuilderAsync(args);

// ...

builder.TestHost.AddTestApplicationLifecycleCallbacks(
    static serviceProvider
    => new CustomTestApplicationLifecycleCallbacks());

ファクトリは IServiceProvider を利用して、テスト プラットフォームで提供されるサービス スイートへのアクセスを取得します。

Von Bedeutung

API は登録された順序で呼び出されるため、登録のシーケンスは重要です。

インターフェイスには、以下のメソッドが含まれます。

public interface ITestApplicationLifecycleCallbacks : ITestHostExtension
{
    Task BeforeRunAsync(CancellationToken cancellationToken);

    Task AfterRunAsync(
        int exitCode,
        CancellationToken cancellation);
}

public interface ITestHostExtension : IExtension
{
}

は、すべての拡張機能のベースとして機能する の型です。 他のすべての拡張点と同様に、IExtension からも継承されます。 そのため、他の拡張機能と同様に、 API を使用してそれを有効または無効にすることができます。

: このメソッドは、テスト ホストの最初の接触点として機能し、インプロセス拡張機能が機能を実行する最初の機会です。 通常、機能が両方の環境で動作するように設計されている場合、対応するアウトプロセス拡張機能との接続を確立するために使用されます。

例えば、組み込みのハング ダンプ機能は、インプロセスとアウトプロセスの両方の拡張機能で構成されており、このメソッドは拡張機能のアウトプロセス コンポーネントと情報を交換するために使用されます。

: このメソッドは を終了する前の最後の呼び出しであり、 を提供します。 これは、もっぱらクリーンアップ タスクのためと、対応するアウトプロセス拡張機能にテスト ホストが終了しようとしていることを通知するために使用する必要があります。

最後に、どちらの API も、拡張機能が受け入れる必要がある を取得します。

拡張

は、インプロセス拡張機能で、およびその拡張機能によって にプッシュされる 情報を購読および受信することができます。

この拡張点は、それによって開発者がテスト セッション中に生成されたすべての情報を収集して処理できるため、非常に重要です。

カスタム を登録するには、次の API を利用します。

var builder = await TestApplication.CreateBuilderAsync(args);

// ...

builder.TestHost.AddDataConsumer(
    static serviceProvider => new CustomDataConsumer());

ファクトリは IServiceProvider を利用して、テスト プラットフォームで提供されるサービス スイートへのアクセスを取得します。

Von Bedeutung

API は登録された順序で呼び出されるため、登録のシーケンスは重要です。

インターフェイスには、以下のメソッドが含まれます。

public interface IDataConsumer : ITestHostExtension
{
    Type[] DataTypesConsumed { get; }

    Task ConsumeAsync(
        IDataProducer dataProducer,
        IData value,
        CancellationToken cancellationToken);
}

public interface IData
{
    string DisplayName { get; }
    string? Description { get; }
}

は、すべての拡張機能のベースとして機能する の型です。 他のすべての拡張点と同様に、IExtension からも継承されます。 そのため、他の拡張機能と同様に、 API を使用してそれを有効または無効にすることができます。

: このプロパティは、この拡張機能が使用する予定の の一覧を返します。 これは に対応します。 特に、 は異なる インスタンスから発生した複数の型を問題なくサブスクライブできます。

: このメソッドは、現在のコンシューマーがサブスクライブされている型のデータが にプッシュされるたびにトリガーされます。 を受け取って、データ ペイロードのプロデューサーと ペイロード自体に関する詳細を提供します。 ご覧のように、 は、一般的な情報データを含む汎用プレースホルダー インターフェイスです。 さまざまな種類の をプッシュする能力は、コンシューマーが種類自体を切り替えることで、それを正しい種類にキャストし、特定の情報にアクセスする必要があることを意味します。

テストフレームワークによって生成されたを詳細に扱うコンシューマの実装例としては、次のようなものがあります。

internal class CustomDataConsumer : IDataConsumer, IOutputDeviceDataProducer
{
    public Type[] DataTypesConsumed => new[] { typeof(TestNodeUpdateMessage) };
    ...
    public Task ConsumeAsync(
        IDataProducer dataProducer,
        IData value,
        CancellationToken cancellationToken)
    {
        var testNodeUpdateMessage = (TestNodeUpdateMessage)value;

        switch (testNodeUpdateMessage.TestNode.Properties.Single<TestNodeStateProperty>())
        {
            case InProgressTestNodeStateProperty _:
                {
                    ...
                    break;
                }
            case PassedTestNodeStateProperty _:
                {
                    ...
                    break;
                }
            case FailedTestNodeStateProperty failedTestNodeStateProperty:
                {
                    ...
                    break;
                }
            case SkippedTestNodeStateProperty _:
                {
                    ...
                    break;
                }
            ...
        }

        return Task.CompletedTask;
    }
...
}

最後に、API は拡張機能が受け入れると想定されている を取得します。

Von Bedeutung

メソッド内でペイロードを直接処理することが重要です。 IMessageBus は、同期処理と非同期処理の両方を管理し、テスト フレームワークを使用して実行を調整できます。 消費プロセスは完全に非同期で、書き込み時に IMessageBus.Push をブロックすることはありませんが、これは将来の要件により今後変更される可能性のある実装の詳細です。 ただし、このプラットフォームでは、このメソッドが常に 1 回呼び出されるため、複雑な同期が不要になります。また、コンシューマーのスケーラビリティも管理されます。

Warnung

で ITestHostProcessLifetimeHandler を composite extension point 内で使用する場合は、ITestSessionLifetimeHandler.OnTestSessionFinishingAsync の実行後に受信したデータを無視することが重要です。 は、蓄積されたデータを処理し、新しい情報を IMessageBus に送信する最後の機会であるため、この時点以降に使用されるデータは拡張機能では利用できません。

拡張機能が集中的な初期化を必要としており、ユーザーが async/await パターンを使用する必要がある場合には、 を参照できます。 拡張点の間で状態を共有する必要がある場合は、 セクションを参照できます。

拡張

は、テスト ホストのカスタム環境変数を確立できるアウトプロセス拡張機能です。 この拡張点を使用すると、アーキテクチャ セクションで詳しく説明したように、テスト プラットフォームが適切な環境変数を使用して新しいホストを開始できるようになります。

カスタム を登録するには、次の API を利用します。

var builder = await TestApplication.CreateBuilderAsync(args);

// ...

builder.TestHostControllers.AddEnvironmentVariableProvider(
    static serviceProvider => new CustomEnvironmentVariableForTestHost());

ファクトリは IServiceProvider を利用して、テスト プラットフォームで提供されるサービス スイートへのアクセスを取得します。

Von Bedeutung

API は登録された順序で呼び出されるため、登録のシーケンスは重要です。

インターフェイスには、以下のメソッドと型が含まれます。

public interface ITestHostEnvironmentVariableProvider : ITestHostControllersExtension, IExtension
{
    Task UpdateAsync(IEnvironmentVariables environmentVariables);

    Task<ValidationResult> ValidateTestHostEnvironmentVariablesAsync(
        IReadOnlyEnvironmentVariables environmentVariables);
}

public interface IEnvironmentVariables : IReadOnlyEnvironmentVariables
{
    void SetVariable(EnvironmentVariable environmentVariable);
    void RemoveVariable(string variable);
}

public interface IReadOnlyEnvironmentVariables
{
    bool TryGetVariable(
        string variable,
        [NotNullWhen(true)] out OwnedEnvironmentVariable? environmentVariable);
}

public sealed class OwnedEnvironmentVariable : EnvironmentVariable
{
    public IExtension Owner { get; }

    public OwnedEnvironmentVariable(
        IExtension owner,
        string variable,
        string? value,
        bool isSecret,
        bool isLocked);
}

public class EnvironmentVariable
{
    public string Variable { get; }
    public string? Value { get; }
    public bool IsSecret { get; }
    public bool IsLocked { get; }
}

は、あらゆる拡張の基盤となるの一種です。 他のすべての拡張点と同様に、IExtension からも継承されます。 そのため、他の拡張機能と同様に、 API を使用してそれを有効または無効にすることができます。

この API の詳細に注意を払いましょう。

: この更新 API は オブジェクトのインスタンスを提供し、そこから または のメソッドを呼び出すことができます。 を使用する場合は、次の仕様を必要とする型 のオブジェクトを渡す必要があります。

  • : 環境変数の名前。
  • : 環境変数の値。
  • : これは、 を使用してログを作成したりアクセスしたりしてはならない機密情報が環境変数に含まれているかどうかを示します。
  • : これにより、他の 拡張機能がこの値を変更できるかどうかが決まります。

: このメソッドは、登録済みの インスタンスのすべての メソッドが呼び出された後に呼び出されます。 環境変数の正しいセットアップを確認できます。 を実装するオブジェクトを取得すると、 オブジェクト型を使用して特定の環境変数情報をフェッチする メソッドが提供されます。 検証後、エラーの理由が含まれている を返します。

テスト プラットフォームは、既定で、 を実装して登録します。 このプロバイダーは、現在のすべての環境変数を読み込みます。 それは、最初に登録されたプロバイダーとして最初に実行され、他のすべての ユーザー拡張機能に対して既定の環境変数へのアクセスが付与されます。

拡張機能が集中的な初期化を必要としており、ユーザーが async/await パターンを使用する必要がある場合には、 を参照できます。 拡張点の間で状態を共有する必要がある場合は、 セクションを参照できます。

拡張

はアウトプロセス拡張機能で、外部の観点からテスト ホスト プロセスを観察できます。 これにより、テスト対象のコードによって誘発される可能性のあるクラッシュやハングの影響を、拡張機能が受けないようにします。 この拡張点を利用すると、アーキテクチャ セクションで詳しく説明したように、テスト プラットフォームは新しいホストを開始するように求められます。

カスタム を登録するには、次の API を利用します。

var builder = await TestApplication.CreateBuilderAsync(args);

// ...

builder.TestHostControllers.AddProcessLifetimeHandler(
    static serviceProvider => new CustomMonitorTestHost());

ファクトリは IServiceProvider を利用して、テスト プラットフォームで提供されるサービス スイートへのアクセスを取得します。

Von Bedeutung

API は登録された順序で呼び出されるため、登録のシーケンスは重要です。

インターフェイスには、以下のメソッドが含まれます。

public interface ITestHostProcessLifetimeHandler : ITestHostControllersExtension
{
    Task BeforeTestHostProcessStartAsync(CancellationToken cancellationToken);

    Task OnTestHostProcessStartedAsync(
        ITestHostProcessInformation testHostProcessInformation,
        CancellationToken cancellation);

    Task OnTestHostProcessExitedAsync(
        ITestHostProcessInformation testHostProcessInformation,
        CancellationToken cancellation);
}

public interface ITestHostProcessInformation
{
    int PID { get; }
    int ExitCode { get; }
    bool HasExitedGracefully { get; }
}

は、あらゆる拡張の基盤となるの一種です。 他のすべての拡張点と同様に、IExtension からも継承されます。 そのため、他の拡張機能と同様に、 API を使用してそれを有効または無効にすることができます。

この API の詳細に注意を払いましょう。

: このメソッドは、テスト プラットフォームがテスト ホストを開始する前に呼び出されます。

: このメソッドは、テスト ホストの開始直後に呼び出されます。 このメソッドは、テスト ホスト プロセスの結果に関する重要な詳細を提供する インターフェイスを実装するオブジェクトを提供します。

Von Bedeutung

このメソッドを呼び出しても、テスト ホストの実行は停止しません。 一時停止する必要がある場合は、インプロセス拡張機能を として登録し、アウトプロセス拡張機能と同期する必要があります。

: このメソッドは、テスト スイートの実行が完了したときに呼び出されます。 このメソッドは、テスト ホスト プロセスの結果に関する重要な詳細を伝える インターフェイスに準拠したオブジェクトを提供します。

インターフェイスでは、次の詳細が提供されます。

  • : テスト ホストのプロセス ID。
  • : プロセスの終了コード。 この値は、 メソッド内でのみ使用できます。 メソッド内でアクセスしようとすると、例外が発生します。
  • : テスト ホストがクラッシュしたかどうかを示すブール値。 true の場合は、テスト ホストが正常に終了しなかったことを示します。

拡張機能の実行順序

テスト プラットフォームは、テスト フレームワークと、インプロセスまたはアウトプロセスを操作できる任意の数の拡張機能で構成されます。 このドキュメントでは、機能が呼び出されるタイミングの想定について明確にするために、すべての潜在的な拡張ポイントの呼び出しのシーケンスについて説明します。

  1. ITestHostEnvironmentVariableProvider.UpdateAsync : アウトプロセス
  2. ITestHostEnvironmentVariableProvider.ValidateTestHostEnvironmentVariablesAsync : プロセス外
  3. ITestHostProcessLifetimeHandler.BeforeTestHostProcessStartAsync : プロセス外実行
  4. ホストプロセスのテスト開始
  5. ITestHostProcessLifetimeHandler.OnTestHostProcessStartedAsync : プロセス外で、このイベントは競合状態によりプロセス内拡張機能の動作が絡み合う可能性があります。
  6. ITestApplicationLifecycleCallbacks.BeforeRunAsync: インプロセス
  7. ITestSessionLifetimeHandler.OnTestSessionStartingAsync: インプロセス
  8. ITestFramework.CreateTestSessionAsync: プロセス内
  9. ITestFramework.ExecuteRequestAsync: インプロセス、このメソッドは 1 回以上呼び出すことができます。 この時点で、テスト フレームワークは IDataConsumer で利用できる情報を IMessageBus に送信します。
  10. ITestFramework.CloseTestSessionAsync: インプロセス
  11. ITestSessionLifetimeHandler.OnTestSessionFinishingAsync: プロセス内
  12. ITestApplicationLifecycleCallbacks.AfterRunAsync: インプロセス
  13. インプロセス クリーンアップでは、すべての拡張点で Dispose と IAsyncCleanableExtension を呼び出す必要があります。
  14. ITestHostProcessLifetimeHandler.OnTestHostProcessExitedAsync : プロセス外
  15. アウトプロセス クリーンアップでは、すべての拡張点で Dispose と IAsyncCleanableExtension を呼び出す必要があります。

拡張機能ヘルパー

テスト プラットフォームには、拡張機能の実装を簡素化するためのヘルパー クラスおよびインターフェースのセットが用意されています。 これらのヘルパーは、開発プロセスを合理化し、拡張機能がプラットフォームの標準に準拠するように設計されています。

拡張機能の非同期初期化とクリーンアップ

ファクトリを介したテスト フレームワークと拡張機能の作成は、同期コンストラクターを使用する標準的な.NET オブジェクト作成メカニズムに準拠しています。 拡張機能が集中的な初期化 (ファイル システムまたはネットワークへのアクセスなど) を必要とする場合、コンストラクターは ではなく void を返すため、コンストラクタで パターンを使用することはできません。

そのため、テスト プラットフォームには、単純なインターフェイス経由で async/await パターンを使用して拡張機能を初期化するメソッドが用意されています。 対称性のために、拡張機能がシームレスに実装できるクリーンアップ用の非同期インターフェイスも提供されます。

public interface IAsyncInitializableExtension
{
    Task InitializeAsync();
}

public interface IAsyncCleanableExtension
{
    Task CleanupAsync();
}

: このメソッドは、作成ファクトリの後で確実に呼び出されます。

: このメソッドは、少なくとも1回、テストセッションの終了時に、既定の または の前にに確実に呼び出されます。

Von Bedeutung

標準 メソッドと同様に、 を複数回呼び出すことができます。 オブジェクトのメソッドが 2 回以上呼び出された場合、オブジェクトは、最初の呼び出しの後すべての呼び出しを無視する必要があります。 オブジェクトは、 メソッドが複数回呼び出される場合、例外をスローしてはなりません。

既定では、テスト プラットフォームは (使用可能な場合) または (実装されている場合) を呼び出します。 テスト プラットフォームでは両方の Dispose メソッドが呼び出されるのではなく、実装されている場合には非同期メソッドが優先されることに注意することが重要です。

CompositeExtensionFactoryT

拡張セクションで説明したように、このテスト プラットフォームでは、インプロセスとアウトプロセスの両方にカスタム拡張機能を組み込むためのインターフェースを実装できます。

各インターフェイスは特定の機能に対応し、.NET設計に従って、このインターフェイスを特定のオブジェクトに実装します。 拡張機能自体は、対応するセクションで詳しく説明されているように、 の特定の登録 API または の オブジェクトを使用して登録できます。

ただし、2 つの拡張機能間で状態を共有する必要がある場合、異なるインターフェースを実装する異なるオブジェクトを実装して登録できるため、共有は困難なタスクになります。 支援がなければ、一方の拡張機能をもう一方の拡張機能に渡して情報を共有する方法が必要になるため、設計は複雑になります。

そのため、テスト プラットフォームでは、同じ型を使用して複数の拡張点を実装する高度なメソッドを用意して、データ共有を簡単なタスクにしています。 必要なのは、1 回のインターフェイス実装で使用するものと同じ API を使用して登録できる、 を利用することです。

と の両方を実装する型を例に考えてみましょう。 これは一般的なシナリオです。なぜなら、ユーザーはテスト フレームワークから情報を収集し、テスト セッションが終了したら、 内の を使用してアーティファクトを送信することが多いからです。

通常、行うべきことはインターフェイスの実装です。

internal class CustomExtension : ITestSessionLifetimeHandler, IDataConsumer, ...
{
   ...
}

型に対して を作成したら、 のオーバーロードを提供する API と API の両方に登録できます。

var builder = await TestApplication.CreateBuilderAsync(args);

// ...

var factory = new CompositeExtensionFactory<CustomExtension>(serviceProvider => new CustomExtension());

builder.TestHost.AddTestSessionLifetimeHandle(factory);
builder.TestHost.AddDataConsumer(factory);

ファクトリ コンストラクターは、IServiceProvider を使用して、テスト プラットフォームによって提供されるサービスにアクセスします。

テスト プラットフォームは、複合拡張機能のライフサイクルを管理する役割を担います。

インプロセス拡張機能とアウトプロセス拡張機能の両方に対するテスト プラットフォームのサポートにより、拡張点を任意に組み合わせることができないことに注意してください。 拡張機能の作成と利用はホストの種類に依存します。つまり、インプロセス (TestHost) とアウトプロセス (TestHostController) の拡張機能のみグループ化できます。

次の組み合わせが可能です。

  • の場合は、 と を組み合わせることができます。
  • の場合は、 と を組み合わせることができます。