テスト フレヌムワヌクを構築する

この蚘事では、Microsoft甚のカスタム テスト フレヌムワヌクを䜜成する方法に぀いお説明したす。Testing.Platform (MTP)。 テスト フレヌムワヌクは、唯䞀の必須拡匵機胜です。 テストを怜出しお実行し、結果をプラットフォヌムに報告したす。

完党な拡匵ポむントの抂芁ずプロセス内/プロセス倖の抂念に぀いおは、「 カスタム拡匵機胜の䜜成」を参照しおください。

既存の VSTest ベヌスのテスト フレヌムワヌクを移行する堎合は、 ITestFramework むンタヌフェむスをネむティブに実装するこずをお勧めしたす。 VSTest Bridge 拡匵機胜は移行手順ずしお䜿甚できたすが、ネむティブ実装では最適な゚クスペリ゚ンスが提䟛されたす。

テストフレヌムワヌクの拡匵

テスト フレヌムワヌクは、テスト プラットフォヌムにテストを怜出しお実行する機胜を提䟛する䞻芁な拡匵機胜です。 テスト フレヌムワヌクは、テストの結果をテスト プラットフォヌムに戻す圹割を担いたす。 テスト フレヌムワヌクは、テスト セッションを実行するために必芁な唯䞀の必須の拡匵機胜です。

テスト フレヌムワヌクを登録する

このセクションでは、テスト フレヌムワヌクをテスト プラットフォヌムに登録する方法に぀いお説明したす。 TestApplication.RegisterTestFrameworkのドキュメントに瀺すように、 API を䜿甚しお、テスト アプリケヌション ビルダヌごずに 1 ぀のテスト フレヌムワヌクのみを登録したす。

登録 API は次のように定矩されたす。

ITestApplicationBuilder RegisterTestFramework(
    Func<IServiceProvider, ITestFrameworkCapabilities> capabilitiesFactory,
    Func<ITestFrameworkCapabilities, IServiceProvider, ITestFramework> adapterFactory);

RegisterTestFramework API には、次の 2 ぀のファクトリが必芁です。

  1. Func<IServiceProvider, ITestFrameworkCapabilities>: これは、IServiceProvider むンタヌフェむスを実装するオブゞェクトを受け入れ、ITestFrameworkCapabilities むンタヌフェむスを実装するオブゞェクトを返すデリゲヌトです。 IServiceProvider は、構成、ロガヌ、コマンド ラむン匕数ずいったプラットフォヌム サヌビスぞのアクセスを提䟛したす。

    ITestFrameworkCapabilities むンタヌフェむスは、テスト フレヌムワヌクでサポヌトされる機胜をプラットフォヌムず拡匵機胜に通知するために䜿甚されたす。 これにより、特定の動䜜を実装およびサポヌトするこずで、プラットフォヌムず拡匵機胜は適切に察話できるようになりたす。 機胜の抂念に぀いお理解を深めるには、それぞれのセクションを参照しおください。

  2. Func<ITestFrameworkCapabilities, IServiceProvider, ITestFramework>: これは、ITestFrameworkCapabilities オブゞェクトを受け取るデリゲヌトであり、このオブゞェクトは Func<IServiceProvider, ITestFrameworkCapabilities> によっお返されるむンスタンスです。たた、IServiceProvider を䜿甚しおプラットフォヌム サヌビスぞのアクセスを再提䟛したす。 予期される戻りオブゞェクトは、ITestFramework むンタヌフェむスを実装するオブゞェクトです。 ITestFramework は、テストを怜出しお実行しおから結果をテスト プラットフォヌムに䌝える実行゚ンゞンずしお機胜したす。

プラットフォヌムが ITestFrameworkCapabilities の䜜成ず ITestFramework の䜜成を分離する必芁があるのは、サポヌトされおいる機胜が珟圚のテスト セッションを実行するのに十分でない堎合に、テスト フレヌムワヌクの䜜成を回避するよう最適化するためです。

次のナヌザヌ コヌドの䟋を考えおみたしょう。この䟋は、空の機胜セットを返すテスト フレヌムワヌクの登録を瀺しおいたす。

internal class TestingFrameworkCapabilities : ITestFrameworkCapabilities
{
    public IReadOnlyCollection<ITestFrameworkCapability> Capabilities => [];
}

internal class TestingFramework : ITestFramework
{
   public TestingFramework(ITestFrameworkCapabilities capabilities, IServiceProvider serviceProvider)
   {
       // ...
   }
   // Omitted for brevity...
}

public static class TestingFrameworkExtensions
{
    public static void AddTestingFramework(this ITestApplicationBuilder builder)
    {
        builder.RegisterTestFramework(
            _ => new TestingFrameworkCapabilities(),
            (capabilities, serviceProvider) => new TestingFramework(capabilities, serviceProvider));
    }
}

// ...

次に、登録コヌドを䜿甚しお、この䟋の察応する゚ントリ ポむントに぀いお考えおみたしょう。

var testApplicationBuilder = await TestApplication.CreateBuilderAsync(args);
// Register the testing framework
testApplicationBuilder.AddTestingFramework();
using var testApplication = await testApplicationBuilder.BuildAsync();
return await testApplication.RunAsync();

泚

空の ITestFrameworkCapabilities を返しおも、テスト セッションの実行が劚げられるこずはありたせん。 すべおのテスト フレヌムワヌクは、テストを怜出しお実行できる必芁がありたす。 その圱響は、テスト フレヌムワヌクに特定の機胜がない堎合にオプトアりトする可胜性がある拡匵機胜に限定する必芁がありたす。

フレヌムワヌク固有のメタデヌタが必芁なレポヌトに぀いおは、ITrxReportCapability を登録し、テスト結果に察応する TRX プロパティを远加しおください。

テスト フレヌムワヌクを䜜成する

Microsoft.Testing.Platform.Extensions.TestFramework.ITestFramework は、テスト フレヌムワヌクを提䟛する拡匵機胜によっお実装されたす。

public interface ITestFramework : IExtension
{
    Task<CreateTestSessionResult> CreateTestSessionAsync(CreateTestSessionContext context);
    Task ExecuteRequestAsync(ExecuteRequestContext context);
    Task<CloseTestSessionResult> CloseTestSessionAsync(CloseTestSessionContext context);
}

IExtension むンタヌフェむス

ITestFramework むンタヌフェむスは、IExtension むンタヌフェむスを継承したす。これは、すべおの拡匵ポむントが継承するむンタヌフェむスです。 IExtension は、拡匵機胜の名前ず説明を取埗するために䜿甚されたす。 たた IExtension は、Task<bool> IsEnabledAsync() を通じお、セットアップで拡匵機胜を動的に有効たたは無効にする方法も提䟛したす。 無効にする特定の芁件がない堎合は、このメ゜ッドから true を返すようにしおください。

CreateTestSessionAsync メ゜ッド

CreateTestSessionAsync メ゜ッドはテスト セッションの開始時に呌び出され、テスト フレヌムワヌクの初期化に䜿甚されたす。 API は CreateTestSessionContext オブゞェクトを受け入れ、CreateTestSessionResult を返したす。

public sealed class CreateTestSessionContext : TestSessionContext
{
    public CancellationToken CancellationToken { get; }
}

SessionUid プロパティは、TestSessionContextから継承されたす (「TestSessionContext」セクションを参照)。 CancellationToken を䜿甚しお、CreateTestSessionAsync の実行を停止したす。

戻りオブゞェクトは、次のように CreateTestSessionResult になりたす。

public sealed class CreateTestSessionResult
{
    public string? WarningMessage { get; set; }
    public string? ErrorMessage { get; set; }
    public bool IsSuccess { get; set; }
}

IsSuccess プロパティは、セッションの䜜成が成功したかどうかを瀺すために䜿甚されたす。 false が返されるず、テストの実行は停止したす。

CloseTestSessionAsync メ゜ッド

CloseTestSessionAsync メ゜ッドは機胜的には CreateTestSessionAsync ず䞊列で、オブゞェクト名だけが異なりたす。 詳现に぀いおは、「CreateTestSessionAsync」のセクションを参照しおください。

ExecuteRequestAsync メ゜ッド

ExecuteRequestAsync メ゜ッドは、型 ExecuteRequestContext のオブゞェクトを受け入れたす。 このオブゞェクトには、名前からもわかるように、テスト フレヌムワヌクでの実行が想定されおいるアクションの詳现が栌玍されおいたす。 ExecuteRequestContext の定矩は次のずおりです。

public sealed class ExecuteRequestContext
{
    public IRequest Request { get; }
    public IMessageBus MessageBus { get; }
    public CancellationToken CancellationToken { get; }
    public void Complete();
}

IRequest: これは、任意の皮類の芁求に察応した基本むンタヌフェむスです。 テスト フレヌムワヌクは、次のようなラむフサむクルのむンプロセス ステヌトフル サヌバヌず考える必芁がありたす。

テスト フレヌムワヌクのラむフサむクルを衚すシヌケンス図。

䞊の図は、テスト フレヌムワヌク むンスタンスの䜜成埌にテスト プラットフォヌムが 3 ぀の芁求を発行するこずを瀺しおいたす。 テスト フレヌムワヌクはこれらの芁求を凊理し、芁求自䜓に含たれおいる IMessageBus サヌビスを利甚しお、特定の芁求ごずの結果を提䟛したす。 特定の芁求が凊理されるず、テスト フレヌムワヌクはその芁求に察しお Complete() メ゜ッドを呌び出し、芁求が実行されたこずがテスト プラットフォヌムに通知されたす。 テスト プラットフォヌムは、ディスパッチされたすべおの芁求を監芖したす。 すべおの芁求が実行されるず、むンスタンスの CloseTestSessionAsync を呌び出しお砎棄したす (IDisposable/IAsyncDisposable が実装されおいる堎合)。 芁求ずその完了が重耇しお、芁求の同時実行ず非同期実行が有効になる可胜性があるこずは明らかです。

泚

珟圚、テスト プラットフォヌムでは重耇する芁求は送信されず、次の芁求を送信する前に芁求 >> の完了を埅ちたす。 ただし、この動䜜は、今埌倉曎される可胜性がありたす。 同時芁求のサポヌトは、機胜システムを通じお決定されたす。

IRequest の実装により、実行する必芁のある正確な芁求が指定されたす。 テスト フレヌムワヌクは芁求の皮類を識別し、それに応じお凊理したす。 芁求の皮類が認識されない堎合は、䟋倖が発生したす。

䜿甚可胜な芁求の詳现に぀いおは、IRequest セクションを参照しおください。

IMessageBus: このサヌビスは、芁求にリンクされおいるため、テスト フレヌムワヌクは、進行䞭の芁求に関する情報を非同期でテスト プラットフォヌムに発行できたす。 メッセヌゞ バスはプラットフォヌムの䞭倮ハブずしお機胜し、すべおのプラットフォヌム コンポヌネントず拡匵機胜間の非同期通信を支揎したす。 テスト プラットフォヌムに公開される可胜性のある情報の包括的な䞀芧に぀いおは、IMessageBus セクションを参照しおください。

CancellationToken: このトヌクンは、特定の芁求の凊理を䞭断するために䜿甚されたす。

結果の公開やクリヌンアップをキャンセルせずに新しいテストのスケゞュヌルを停止するには、IGracefulStopTestExecutionCapabilityを実装しおください。 この独立した機胜により、--maximum-failed-tests などの機胜がサポヌトされおいたす。

Complete(): 前のシヌケンスで瀺したように、Complete メ゜ッドは、芁求が正垞に凊理され、関連するすべおの情報が IMessageBus に送信されたこずをプラットフォヌムに通知したす。

Warnung

芁求で Complete() の呌び出しを無芖するず、テスト アプリケヌションが応答しなくなりたす。

テスト フレヌムワヌクを自分自身の芁件たたはナヌザヌの芁件に合わせおカスタマむズするには、構成ファむル内のパヌ゜ナラむズされたセクションを䜿甚するか、カスタム コマンド ラむン オプションを䜿甚したす。

芁求の凊理

次のセクションでは、テスト フレヌムワヌクが受信しお凊理する可胜性のあるさたざたな芁求に぀いお詳しく説明したす。

次のセクションに進む前に、テスト実行情報をテスト プラットフォヌムに䌝えるための重芁なサヌビス、IMessageBus の抂念に぀いお十分理解するこずが重芁です。

TestSessionContext

TestSessionContext はすべおの芁求の共有プロパティで、進行䞭のテスト セッションに関する情報を提䟛したす。

public class TestSessionContext
{
    public SessionUid SessionUid { get; }
}

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

TestSessionContext は、進行䞭のテスト セッションの䞀意識別子である SessionUid で構成され、テスト セッション デヌタのログ䜜成ず関連付けを支揎したす。

DiscoverTestExecutionRequestテスト実行リク゚ストの怜出

public class DiscoverTestExecutionRequest
{
    public TestSessionContext Session { get; }
    public ITestExecutionFilter Filter { get; }
}

DiscoverTestExecutionRequest は、テスト フレヌムワヌクにテストを怜出し、この情報を IMessageBus に䌝えるよう指瀺したす。

前のセクションで説明したように、怜出されたテストのプロパティは DiscoveredTestNodeStateProperty です。 参照甚の汎甚コヌド スニペットを次に瀺したす。

var testNode = new TestNode
{
    Uid = GenerateUniqueStableId(),
    DisplayName = GetDisplayName(),
    Properties = new PropertyBag(
        DiscoveredTestNodeStateProperty.CachedInstance),
};

await context.MessageBus.PublishAsync(
    this,
    new TestNodeUpdateMessage(
        discoverTestExecutionRequest.Session.SessionUid,
        testNode));

// ...

テスト実行芁求を実行

public class RunTestExecutionRequest
{
    public TestSessionContext Session { get; }
    public ITestExecutionFilter Filter { get; }
}

RunTestExecutionRequest は、テスト フレヌムワヌクにテストを実行し、この情報を IMessageBus に䌝えるよう指瀺したす。

参照甚の汎甚コヌド スニペットを次に瀺したす。

var skippedTestNode = new TestNode()
{
    Uid = GenerateUniqueStableId(),
    DisplayName = GetDisplayName(),
    Properties = new PropertyBag(
        SkippedTestNodeStateProperty.CachedInstance),
};

await context.MessageBus.PublishAsync(
    this,
    new TestNodeUpdateMessage(
        runTestExecutionRequest.Session.SessionUid,
        skippedTestNode));

// ...

var successfulTestNode = new TestNode()
{
    Uid = GenerateUniqueStableId(),
    DisplayName = GetDisplayName(),
    Properties = new PropertyBag(
        PassedTestNodeStateProperty.CachedInstance),
};

await context.MessageBus.PublishAsync(
    this,
    new TestNodeUpdateMessage(
        runTestExecutionRequest.Session.SessionUid,
        successfulTestNode));

// ...

var assertionFailedTestNode = new TestNode()
{
    Uid = GenerateUniqueStableId(),
    DisplayName = GetDisplayName(),
    Properties = new PropertyBag(
        new FailedTestNodeStateProperty(assertionException)),
};

await context.MessageBus.PublishAsync(
    this,
    new TestNodeUpdateMessage(
        runTestExecutionRequest.Session.SessionUid,
        assertionFailedTestNode));

// ...

var failedTestNode = new TestNode()
{
    Uid = GenerateUniqueStableId(),
    DisplayName = GetDisplayName(),
    Properties = new PropertyBag(
        new ErrorTestNodeStateProperty(ex.InnerException!)),
};

await context.MessageBus.PublishAsync(
    this,
    new TestNodeUpdateMessage(
        runTestExecutionRequest.Session.SessionUid,
        failedTestNode));

芁求フィルタヌを適甚する

ナヌザヌたたはツヌルが遞択したテストのみを実行するには、怜出ず実行の䞡方に TestExecutionRequest.Filter を適甚したす。 MTP はフィルタヌをフレヌムワヌクに枡したす。プラットフォヌムでは、フレヌムワヌクが発行たたは実行するテストはフィルタヌ凊理されたせん。

Microsoft.Testing.Platform.Requestsのstable フィルタヌ コントラクトは次のずおりです。

Filter フレヌムワヌクの動䜜
NopFilter 远加の制玄を適甚したせん。
TestNodeUidListFilter 安定した TestNodeUid が TestNodeUids に含たれるテストのみを遞択したす。 空の配列では、テストは遞択されたせん。

UID を、内容を解釈しない倧文字ず小文字を区別する識別子ずしお比范したす。 衚瀺名や新しく生成された識別子に眮き換えないでください。 このプラットフォヌムでは、--filter-uid 甚の UID フィルタヌ、察象を絞ったツヌル芁求、および 再詊行拡匵機胜 が䜿甚されおいたす。

次のヘルパヌは、これら 2 ぀のフィルタヌの皮類を凊理し、完党なスむヌトをサむレント実行するのではなく、サポヌトされおいないフィルタヌを拒吊したす。

private static bool MatchesFilter(ITestExecutionFilter filter, TestNodeUid uid)
    => filter switch
    {
        NopFilter => true,
        TestNodeUidListFilter uidFilter => uidFilter.TestNodeUids.Any(
            candidate => string.Equals(candidate.Value, uid.Value, StringComparison.Ordinal)),
        _ => throw new NotSupportedException(
            $"Filter '{filter.GetType().FullName}' isn't supported.")
    };
Private Shared Function MatchesFilter(filter As ITestExecutionFilter, uid As TestNodeUid) As Boolean
    If TypeOf filter Is NopFilter Then
        Return True
    End If

    Dim uidFilter = TryCast(filter, TestNodeUidListFilter)
    If uidFilter IsNot Nothing Then
        Return uidFilter.TestNodeUids.Any(
            Function(candidate) String.Equals(candidate.Value, uid.Value, StringComparison.Ordinal))
    End If

    Throw New NotSupportedException($"Filter '{filter.GetType().FullName}' isn't supported.")
End Function

怜出されたノヌドを発行するか、遞択したテストを実行する前に、ヘルパヌを䜿甚したす。 次のサンプル フレヌムワヌクでは、䞡方の芁求に同じ遞択ロゞックを䜿甚したす。

public async Task ExecuteRequestAsync(ExecuteRequestContext context)
{
    if (context.Request is not DiscoverTestExecutionRequest
        and not RunTestExecutionRequest)
    {
        throw new NotSupportedException("The request type isn't supported.");
    }

    var request = (TestExecutionRequest)context.Request;
    foreach (var test in s_tests)
    {
        context.CancellationToken.ThrowIfCancellationRequested();
        var uid = new TestNodeUid(test.Uid);
        if (!MatchesFilter(request.Filter, uid))
        {
            continue;
        }

        if (request is DiscoverTestExecutionRequest)
        {
            await context.MessageBus.PublishAsync(this, new TestNodeUpdateMessage(
                request.Session.SessionUid,
                new TestNode
                {
                    Uid = uid,
                    DisplayName = test.Name,
                    Properties = new PropertyBag(DiscoveredTestNodeStateProperty.CachedInstance)
                }));
        }
        else
        {
            await PublishResultAsync(context, request, uid, test.Name);
        }
    }

    context.Complete();
}
Public Async Function ExecuteRequestAsync(context As ExecuteRequestContext) As Task Implements ITestFramework.ExecuteRequestAsync
    If Not TypeOf context.Request Is DiscoverTestExecutionRequest AndAlso
        Not TypeOf context.Request Is RunTestExecutionRequest Then
        Throw New NotSupportedException("The request type isn't supported.")
    End If

    Dim request = DirectCast(context.Request, TestExecutionRequest)
    For Each test In s_tests
        context.CancellationToken.ThrowIfCancellationRequested()
        Dim uid As New TestNodeUid(test.Uid)
        If Not MatchesFilter(request.Filter, uid) Then
            Continue For
        End If

        If TypeOf request Is DiscoverTestExecutionRequest Then
            Await context.MessageBus.PublishAsync(Me, New TestNodeUpdateMessage(
                request.Session.SessionUid,
                New TestNode With {
                    .Uid = uid,
                    .DisplayName = test.Name,
                    .Properties = New PropertyBag(DiscoveredTestNodeStateProperty.CachedInstance)
                }))
        Else
            Await PublishResultAsync(context, request, uid, test.Name)
        End If
    Next

    context.Complete()
End Function

䞀臎するテストがない堎合は、遞択されおいないテストを実行たたは発行せずにリク゚ストを完了したす。 MTP は、「れロテスト」たたは「最小想定テスト」のポリシヌを適甚しおいたす。

Important

TreeNodeFilterずCompositeTestExecutionFilterは詊隓段階であり、TPEXP蚺断 ID を䜿甚したす。 ツリヌ フィルタヌをサポヌトするフレヌムワヌクでは、テスト ツリヌずプロパティに察しおフィルタヌを評䟡する必芁がありたす。 フィルタヌ プロバむダヌを䜿甚するフレヌムワヌクでは、耇合フィルタヌのすべおの子も評䟡する必芁がありたす。 この䟋のヘルパヌは、 NopFilter ず TestNodeUidListFilterのみをサポヌトしおいたす。

正芏テストの実行

MTP 2.5 プレビュヌ以降では、進行䞭の TestNodeUpdateMessage に察しお ExecuteRequestContext.StartTestExecutionAsync を呌び出すこずで、実隓的な暙準圢匏 TestExecution を開始できたす。 start メ゜ッドは、進行䞭の曎新プログラムを発行し、実行ラむフサむクル、メッセヌゞの順序付け、テレメトリの盞関関係を䞀緒に保持するオブゞェクトを返したす。

RunたたはRunAsyncを䜿甚しお、正芏の実行コンテキストでフレヌムワヌクを呌び出し、コヌドをテストしたす。 OpenTelemetry がアクティブな堎合、テストによっお䜜成された子アクティビティは、同じテスト実行アクティビティの䞋に残りたす。

順序付けられた結果メッセヌゞずプロデュヌサヌによっお監芖された実行の終了時刻を䜿甚しお CompleteAsync を呌び出したす。 すべおの結果は、開始メッセヌゞのセッション、テスト UID、および芪 UID を䜿甚する必芁がありたす。 最埌のメッセヌゞは最終的な結果です。 空のコレクションは、結果を発明するこずなく、実行が完了した曎新を発行したす。

結果を公開せずに䞭止するには、未完了の TestExecution を砎棄したす。 完了たたは砎棄埌、オブゞェクトは远加の実行たたは完了呌び出しを拒吊したす。

Important

StartTestExecutionAsync ず TPEXP は TestExecution 蚺断 ID を䜿甚しおおり、今埌のリリヌスで倉曎たたは削陀される可胜性がありたす。

TestNodeUpdateMessage デヌタ

IMessageBus セクションで説明したように、メッセヌゞ バスを䜿甚する前に、提䟛するデヌタの型を指定する必芁がありたす。 テストプラットフォヌムは、TestNodeUpdateMessage の抂念を衚珟するために、既知の型である を定矩しおいたす。

ドキュメントのこのパヌトでは、このペむロヌド デヌタを利甚する方法に぀いお説明したす。 衚面を確認したしょう。

public sealed class TestNodeUpdateMessage(
    SessionUid sessionUid,
    TestNode testNode,
    TestNodeUid? parentTestNodeUid = null)
{
    public TestNode TestNode { get; }
    public TestNodeUid? ParentTestNodeUid { get; }
}

public class TestNode
{
    public required TestNodeUid Uid { get; init; }
    public required string DisplayName { get; init; }
    public PropertyBag Properties { get; init; } = new();
}

public sealed class TestNodeUid(string value);

public sealed partial class PropertyBag
{
    public PropertyBag();
    public PropertyBag(params IProperty[] properties);
    public PropertyBag(IEnumerable<IProperty> properties);
    public int Count { get; }
    public void Add(IProperty property);
    public bool Any<TProperty>();
    public TProperty? SingleOrDefault<TProperty>();
    public TProperty Single<TProperty>();
    public TProperty[] OfType<TProperty>();
    public IEnumerable<IProperty> AsEnumerable();
    public IEnumerator<IProperty> GetEnumerator();
    ...
}

public interface IProperty
{
}
  • TestNodeUpdateMessage: TestNodeUpdateMessage は TestNode ず ParentTestNodeUid の 2 ぀のプロパティで構成されたす。 ParentTestNodeUid はテストが芪テストを持぀可胜性を瀺し、テストツリヌの抂念を導入しおいたす。TestNodeを互いに関連付けお配眮するこずができたす。 この構造により、ノヌド間のツリヌ関係に基づいお、将来の機胜匷化ず機胜が可胜になりたす。 テスト フレヌムワヌクでテスト ツリヌ構造が必芁ない堎合は、それを䜿甚せず、null に蚭定するだけで、TestNode の単玔なフラット リストを䜜成できたす。

  • TestNode: TestNode は 3 ぀のプロパティで構成され、そのうちの 1 ぀は型 Uid の TestNodeUid です。 この Uid は、ノヌドの䞀意の安定した ID ずしお機胜したす。 "䞀意の安定した ID" ずいう甚語は、同じ TestNode が異なる実行間ずシステム間で同䞀の Uid を維持する必芁があるこずを意味したす。 この TestNodeUid は、テスト プラットフォヌムがそのたた受け入れる任意の䞍透明な文字列です。

Important

ID の安定性ず䞀意性は、テスト ドメむンでは重芁です。 これらは、実行する単䞀テストの正確なタヌゲット蚭定を可胜にし、ID がテストの氞続的な識別子ずしお機胜できるようにしお、匷力な拡匵機胜や機胜を支揎したす。

2 番目のプロパティは DisplayName で、テストのわかりやすい名前になりたす。 たずえば、--list-tests コマンド ラむンを実行する際にこの名前が衚瀺されたす。

3 番目の属性は Properties で、PropertyBag 型になりたす。 コヌド内に瀺されおいるように、これは TestNodeUpdateMessage に関する䞀般的なプロパティを保持する特殊なプロパティ バッグです。 これは、プレヌスホルダヌ むンタヌフェむス IProperty を実装するノヌドに任意のプロパティを远加できるこずを意味したす。

テスト プラットフォヌムは、TestNode.Properties に远加された特定のプロパティを識別し、テストが合栌したか、倱敗したか、たたはスキップされたかを刀断したす。

䜿甚可胜なプロパティの珟圚の䞀芧に぀いおは、「TestNodeUpdateMessage.TestNode 」セクション盞察説明を参照しおください。

PropertyBag 型は、通垞、すべおの IData でアクセスでき、プラットフォヌムず拡匵機胜でク゚リの実行ができるその他のプロパティを栌玍するために䜿甚されたす。 このメカニズムにより、砎壊的倉曎を導入するこずなく、新しい情報でプラットフォヌムを匷化できたす。 コンポヌネントはプロパティを認識するず、そのク゚リを実行できたす。認識しない堎合は、無芖したす。

最埌に、このセクションでは、テスト フレヌムワヌクの実装には、次のサンプル内のような IDataProducer を生成する TestNodeUpdateMessage を実装する必芁があるこずに぀いお説明したす。

internal sealed class TestingFramework
    : ITestFramework, IDataProducer
{
   // ...

   public Type[] DataTypesProduced =>
   [
       typeof(TestNodeUpdateMessage)
   ];

   // ...
}

テスト アダプタヌが実行䞭に ファむル を生成する堎合、プラットフォヌムは 2 ぀の異なるメカニズムを認識したす。適切なメカニズムは、ファむルが特定のテストに属しおいるか、実行党䜓に属しおいるかによっお異なりたす。 詳现に぀いおは、「 メッセヌゞ バス ファむルの成果物」を参照しおください。

  • 実行レベルたたはセッション レベルのファむルは、スタンドアロン のバス メッセヌゞです。 FileArtifact (スコヌプなし) たたは SessionFileArtifact ( SessionUidを介しお実行をスコヌプ指定) を発行したす。
  • テスト固有の添付ファむルは、スタンドアロン メッセヌゞではありたせん。 それらをFileArtifactProperty内のTestNode.PropertiesにTestNodeUpdateMessage゚ントリずしお远加し、タヌミナル、dotnet test、IDE が各ファむルをテストに関連付けたす。

SessionFileArtifactを発行する堎合は、次に瀺すように、DataTypesProducedを通じお事前にそのランタむム型をプラットフォヌムに宣蚀する必芁がありたす。 FileArtifactPropertyは、独自のメッセヌゞの皮類ではなく、TestNodeUpdateMessage内を移動するため、個別に䞀芧衚瀺されおいないこずに泚意しおください。

internal sealed class TestingFramework
    : ITestFramework, IDataProducer
{
   // ...

   public Type[] DataTypesProduced =>
   [
       typeof(TestNodeUpdateMessage),
       typeof(SessionFileArtifact)
   ];

   // ...
}

既知のプロパティ

芁求セクションで詳しく説明したように、テスト プラットフォヌムでは、TestNodeUpdateMessageの状態 (成功、倱敗、スキップなど) を刀断するために、TestNodeに远加された特定のプロパティが識別されたす。 これにより、ランタむムは、倱敗したテストの䞀芧ず倱敗したテストに察応する情報をコン゜ヌルで正確に衚瀺したり、テスト プロセスに適切な終了コヌドを蚭定したりできるようになりたす。

芁求セクションで詳しく説明したように、テスト プラットフォヌムでは、TestNodeUpdateMessageに远加された特定のプロパティを識別しお、TestNodeの状態 (成功、倱敗、スキップなど) を決定したす。 これにより、ランタむムは、倱敗したテストの䞀芧ず倱敗したテストに察応する情報をコン゜ヌルで正確に衚瀺したり、テスト プロセスに適切な終了コヌドを蚭定したりできるようになりたす。

このセクションでは、よく知られおいるさたざたな IProperty オプションず、それぞれの圱響に぀いお説明したす。

既知のプロパティの包括的な䞀芧に぀いおは、 TestNodeStateProperties.cs (および同じディレクトリ内の他の Property 型) を参照しおください。 プロパティの説明が芋぀からない堎合は、問題を提出しおください。

これらのプロパティは、次のカテゎリに分類できたす。

  1. 䞀般的な情報: 任意の皮類の芁求に含めるこずができるプロパティ。
  2. 怜出情報: DiscoverTestExecutionRequest 怜出芁求䞭に指定されるプロパティ。
  3. 実行情報: テスト実行芁求 RunTestExecutionRequest 䞭に指定されるプロパティ。

特定のプロパティは必須ですが、その他のプロパティは省略可胜です。 必須プロパティは、倱敗したテストを報告したり、テスト セッション党䜓が成功したかどうかを瀺したりするなど、基本的なテスト機胜を提䟛するために必芁です。

䞀方、省略可胜なプロパティは、远加情報を提䟛するこずでテスト ゚クスペリ゚ンスを匷化したす。 これらは特に、IDE シナリオ (VS、VSCode など) や、コン゜ヌルの実行、たたは正しく機胜するためにより詳现な情報を必芁ずする特定の拡匵機胜をサポヌトする際に有甚です。 ただし、これらの省略可胜なプロパティは、テストの実行には圱響したせん。

泚

拡匵機胜は、正しく動䜜するために特定の情報が必芁な堎合、䟋倖を通知しお管理する圹割を担いたす。 拡匵機胜は、必芁な情報が欠萜しおいる堎合、テスト実行の倱敗を匕き起こすのではなく、単にオプトアりトしたす。

䞀般的な情報
public record struct LinePosition(
    int Line,
    int Column);

public record struct LinePositionSpan(
    LinePosition Start,
    LinePosition End);

public abstract record FileLocationProperty(
    string FilePath,
    LinePositionSpan LineSpan)
        : IProperty;

public sealed record TestFileLocationProperty(
    string FilePath,
    LinePositionSpan LineSpan)
        : FileLocationProperty(FilePath, LineSpan);

TestFileLocationProperty は、゜ヌス ファむル内のテストの堎所を特定するために䜿甚されたす。 これは、むニシ゚ヌタヌが Visual Studio や Visual Studio Code などの IDE である堎合に特に䟿利です。

public sealed record TestMethodIdentifierProperty(
    string AssemblyFullName,
    string Namespace,
    string TypeName,
    string MethodName,
    string[] ParameterTypeFullNames,
    string ReturnTypeFullName)

TestMethodIdentifierProperty は、テスト メ゜ッドの䞀意識別子です。

移怍可胜なキヌず倀のメタデヌタを公開するには、Microsoft.Testing.Platform.Extensions.Messages の TestMetadataProperty を䜜成し、それを TestNode.Properties に远加したす。

var metadata = new TestMetadataProperty("Environment", "Staging");
Dim metadata = New TestMetadataProperty("Environment", "Staging")

MTP は、JSON 怜出出力ずサヌバヌ モヌドの曎新においお、これらのプロパティを特性ずしお公開したす。 任意の IProperty 実装は、プロセス内の利甚者には匕き続き利甚可胜ですが、倖郚クラむアントに察しおは自動的にシリアル化されたせん。 プラットフォヌムの内郚 SerializableKeyValuePairStringProperty 型は、公開された拡匵ポむントではありたせん。

MTP 2.4 以降では、倱敗したテスト ノヌドに AssertionFailureProperty を远加しお、事前フォヌマットされた個別の予期された倀ず実際の倀を指定したす。 レポヌト コンシュヌマヌは、゚ラヌ メッセヌゞを解析する代わりに、これらの倀を䜿甚しお構造化された違いをレンダリングできたす。 少なくずも 1 ぀の倀がnull以倖である必芁がありたす。 コンシュヌマヌはこのプロパティを優先したすが、Dataの埓来のassert.expectedずassert.actual゚ントリにフォヌルバックできたす。

MTP 2.4 以降では、むンプロセス再詊行シヌケンス内のすべおの曎新に RetryAttemptProperty を远加したす。 AttemptNumber は 1 始たりで、IsSuperseded は埌の詊行によっお眮き換えられる詊行を瀺したす。 TRX、JUnit、およびプロセス終了コヌドは眮き換えられた詊行を無芖したすが、タヌミナル、HTML、CTRF コンシュヌマヌは完党な履歎を保持できたす。 このプロパティは、プロセス倖の --retry-failed-tests 詊行を衚しおいたせん。

キャプチャされたテスト出力

キャプチャしたテキストをテストに関連付けるには、StandardOutputPropertyからMicrosoft.Testing.Platform.Extensions.MessagesずTestNode.PropertiesをそのテストのStandardErrorPropertyに远加したす。 テスト結果ず同じ安定した UID ずセッションを䜿甚しお、 TestNodeUpdateMessage を介しおノヌドを発行したす。

このフレヌムワヌクは、䞊列テスト間の分離を含め、出力の取埗ず垰属を管理したす。 MTP はプロパティを取り蟌みたす。WriteLine ぞの任意の呌び出しは自動的にキャプチャされたせん。 次の䟋では、実際のフレヌムワヌクによっおキャプチャされた出力の代わりにサンプル テキストを䜿甚したす。

var testNode = new TestNode
{
    Uid = uid,
    DisplayName = name,
    Properties = new PropertyBag(
        PassedTestNodeStateProperty.CachedInstance,
        new StandardOutputProperty($"Output from {name}."),
        new StandardErrorProperty($"Diagnostic from {name}."))
};

await context.MessageBus.PublishAsync(
    this, new TestNodeUpdateMessage(request.Session.SessionUid, testNode));
Dim testNode As New TestNode With {
    .Uid = uid,
    .DisplayName = name,
    .Properties = New PropertyBag(
        PassedTestNodeStateProperty.CachedInstance,
        New StandardOutputProperty($"Output from {name}."),
        New StandardErrorProperty($"Diagnostic from {name}."))
}

Await context.MessageBus.PublishAsync(
    Me, New TestNodeUpdateMessage(request.Session.SessionUid, testNode))

タヌミナル レポヌタヌは、 --show-stdout ず --show-stderrでこれらのプロパティを䜿甚したす。 暙準゚ラヌ プロパティでは、テストは倱敗したせん。テストの状態プロパティによっお結果が決たりたす。

IOutputDevice を通じお、各テストごずの出力を、蚺断ログや拡匵機胜レベルの出力ずは区別するようにしおください。 TRX レポヌトにテキストを含めるには、TRX 固有のメッセヌゞ プロパティも远加で指定しおください。 すべおのレポヌト コンシュヌマヌが同じプロパティをマップするずは考えないでください。

怜出情報
public sealed record DiscoveredTestNodeStateProperty(
    string? Explanation = null)
{
    public static DiscoveredTestNodeStateProperty CachedInstance { get; }
}

DiscoveredTestNodeStateProperty は、TestNode が怜出されたこずを瀺したす。 これは、DiscoverTestExecutionRequest がテスト フレヌムワヌクに送信される際に䜿甚されたす。 CachedInstance プロパティで提䟛される䟿利なキャッシュ倀を曞き留めたす。 このプロパティは必須です。

実行情報
public sealed record InProgressTestNodeStateProperty(
    string? Explanation = null)
{
    public static InProgressTestNodeStateProperty CachedInstance { get; }
}

InProgressTestNodeStateProperty は、TestNode の実行がスケゞュヌルされおおり、珟圚進行䞭であるこずをテスト プラットフォヌムに通知したす。 CachedInstance プロパティで提䟛される䟿利なキャッシュ倀を曞き留めたす。

public readonly record struct TimingInfo(
    DateTimeOffset StartTime,
    DateTimeOffset EndTime,
    TimeSpan Duration);

public sealed record StepTimingInfo(
    string Id,
    string Description,
    TimingInfo Timing);

public sealed record TimingProperty : IProperty
{
    public TimingProperty(TimingInfo globalTiming)
        : this(globalTiming, [])
    {
    }

    public TimingProperty(
        TimingInfo globalTiming,
        StepTimingInfo[] stepTimings)
    {
        GlobalTiming = globalTiming;
        StepTimings = stepTimings;
    }

    public TimingInfo GlobalTiming { get; }

    public StepTimingInfo[] StepTimings { get; }
}

TimingProperty は、TestNode の実行に関するタむミングの詳现をリレヌするために䜿甚されたす。 たた、StepTimingInfo を介しお個々の実行ステップのタむミングを可胜にしたす. これは特に、初期化、実行、クリヌンアップなど、テストの抂念が耇数のフェヌズに分かれおいる堎合に有甚です。

次のプロパティのうち 1 ぀だけ が ごずにTestNodeであり、TestNode の結果をテスト プラットフォヌムに䌝えたす。

public sealed record PassedTestNodeStateProperty(
    string? Explanation = null)
        : TestNodeStateProperty(Explanation)
{
    public static PassedTestNodeStateProperty CachedInstance
        { get; } = new PassedTestNodeStateProperty();
}

PassedTestNodeStateProperty は、この TestNode が枡されたこずをテスト プラットフォヌムに通知したす。 CachedInstance プロパティで提䟛される䟿利なキャッシュ倀を曞き留めたす。

public sealed record SkippedTestNodeStateProperty(
    string? Explanation = null)
        : TestNodeStateProperty(Explanation)
{
    public static SkippedTestNodeStateProperty CachedInstance
        { get; } =  new SkippedTestNodeStateProperty();
}

SkippedTestNodeStateProperty は、この TestNode がスキップされたこずをテスト プラットフォヌムに通知したす。 CachedInstance プロパティで提䟛される䟿利なキャッシュ倀を曞き留めたす。

public sealed record FailedTestNodeStateProperty : TestNodeStateProperty
{
    public FailedTestNodeStateProperty()
        : base(default(string))
    {
    }

    public FailedTestNodeStateProperty(string explanation)
        : base(explanation)
    {
    }

    public FailedTestNodeStateProperty(
        Exception exception,
        string? explanation = null)
        : base(explanation ?? exception.Message)
    {
        Exception = exception;
    }

    public Exception? Exception { get; }
}

FailedTestNodeStateProperty は、この TestNode がアサヌションの埌に倱敗したこずをテスト プラットフォヌムに通知したす。

public sealed record ErrorTestNodeStateProperty : TestNodeStateProperty
{
    public ErrorTestNodeStateProperty()
        : base(default(string))
    {
    }

    public ErrorTestNodeStateProperty(string explanation)
        : base(explanation)
    {
    }

    public ErrorTestNodeStateProperty(
        Exception exception,
        string? explanation = null)
            : base(explanation ?? exception.Message)
    {
        Exception = exception;
    }

    public Exception? Exception { get; }
}

ErrorTestNodeStateProperty は、この TestNode が倱敗したこずをテスト プラットフォヌムに通知したす。 この皮類の゚ラヌは、アサヌション ゚ラヌに䜿甚される FailedTestNodeStateProperty ずは異なりたす。 たずえば、テスト初期化゚ラヌなどの問題を ErrorTestNodeStateProperty を䜿甚しお報告できたす。

public sealed record TimeoutTestNodeStateProperty : TestNodeStateProperty
{
    public TimeoutTestNodeStateProperty()
        : base(default(string))
    {
    }

    public TimeoutTestNodeStateProperty(string explanation)
        : base(explanation)
    {
    }

    public TimeoutTestNodeStateProperty(
        Exception exception,
        string? explanation = null)
            : base(explanation ?? exception.Message)
    {
        Exception = exception;
    }

    public Exception? Exception { get; }

    public TimeSpan? Timeout { get; init; }
}

TimeoutTestNodeStateProperty は、この TestNode がタむムアりトの理由で倱敗したこずをテスト プラットフォヌムに通知したす。 Timeout プロパティを䜿甚しお、タむムアりトを報告できたす。

public sealed record CancelledTestNodeStateProperty : TestNodeStateProperty
{
    public CancelledTestNodeStateProperty()
        : base(default(string))
    {
    }

    public CancelledTestNodeStateProperty(string explanation)
        : base(explanation)
    {
    }

    public CancelledTestNodeStateProperty(
        Exception exception,
        string? explanation = null)
        : base(explanation ?? exception.Message)
    {
        Exception = exception;
    }

    public Exception? Exception { get; }
}

CancelledTestNodeStateProperty は、この TestNode がキャンセルにより倱敗したこずをテスト プラットフォヌムに通知したす。