Microsoft.Testing.Platform (MTP) schopnosti

V kontextu MTP funkce odkazuje na potenciál provést konkrétní akci nebo poskytnout konkrétní informace. Je to způsob, jak testovací architektura a rozšíření deklarovat jejich schopnostpracovat určitým způsobem nebo poskytovat konkrétní informace žadatelům .

žadatelé mohou být libovolnou komponentou zapojenou do testovací relace, jako je platforma, rozšíření nebo samotný testovací rámec.

Hlavním cílem systému schopností je usnadnit efektivní komunikaci mezi komponentami zapojenými do testovací relace, která jim umožní exchange informace a přesně splnit jejich potřeby.

Příklad s návodem

Představme si hypotetický příklad, který demonstruje nutnost systému schopností.

Poznámka

Tento příklad je čistě pro ilustrativní účely a v současné době není implementován v rámci MTP ani žádné testovací architektury.

Představte si situaci, kdy máte rozšíření, které vyžaduje, aby testovací architektura najednou nespustí více než jeden test. Kromě toho po každém testu musí rozšíření znát využití procesoru pro tento konkrétní test.

Pokud chcete vyhovět předchozímu scénáři, je potřeba se zeptat testovacího rámce, jestli:

  1. Má možnost provést najednou pouze jeden test.
  2. Může poskytnout informace týkající se množství procesoru spotřebovaného jednotlivými testy.

Jak může rozšíření určit, jestli testovací architektura má schopnost pracovat v tomto režimu a poskytovat informace o využití procesoru pro testovací relaci? V MTP je tato funkce reprezentována implementací rozhraní Microsoft.Testing.Platform.Capabilities.ICapability:

// Base capabilities contracts

public interface ICapability
{
}

public interface ICapabilities<TCapability>
    where TCapability : ICapability
{
    IReadOnlyCollection<TCapability> Capabilities { get; }
}

// Specific testing framework capabilities

public interface ITestFrameworkCapabilities : ICapabilities<ITestFrameworkCapability>
{
}

public interface ITestFrameworkCapability : ICapability
{
}

Jak vidíte, rozhraní ICapability je značkou rozhraní, protože může představovat jakékoli schopnostia skutečná implementace bude závislá na kontextu. Uvidíte také ITestFrameworkCapability, který dědí z ICapability ke klasifikaci schopností. Obecná povaha systému schopností umožňuje pohodlné seskupení podle kontextu. ITestFrameworkCapability seskupí všechny možnosti implementované testovací architekturou. Rozhraní ICapabilities<TCapability> odhalí sadu všech funkcí implementovaných rozšířením. Podobně pro základ existuje kontextová testovací architektura s názvem ITestFrameworkCapabilities. ITestFrameworkCapabilities se poskytuje platformě během procesu registrace testovacího frameworku.

Pokud chcete vytvořit funkci, která řeší výše uvedený scénář, definujete ji následujícím způsobem:

public interface IDisableParallelismCapability : ITestFrameworkCapability
{
    bool CanDisableParallelism { get; }
    bool CanProvidePerTestCpuConsumption { get; }
    void Enable();
}

Pokud testovací architektura implementuje toto rozhraní za běhu, může být dotazováno následující:

  • Ověřte, jestli testovací architektura má možnost vypnout paralelismus CanDisableParallelism = true.
  • Zjistěte, jestli testovací architektura může poskytovat data o využití procesoru CanProvidePerTestCPUConsumption = true.
  • Požádejte testovací adaptér o aktivaci tohoto režimu vyvoláním metody Enable() před zahájením testovací relace.

Hypotetický fragment kódu uvnitř rozšíření by mohl vypadat přibližně takto:

IServiceProvider serviceProvider = null; // TODO: Get IServiceProvider.
var capabilities = serviceProvider.GetRequiredService<ITestFrameworkCapabilities>();

// Utilize the `GetCapability` API to search for the specific capability to query.
var capability = capabilities.GetCapability<IDisableParallelismCapability>();
if (capability is null)
{
    // Capability not supported...
}
else
{
    capability.Enable();
    if (capability.CanDisableParallelism)
    {
        // Do something...
    }

    if (capability.CanProvidePerTestCpuConsumption)
    {
        // Do something...
    }
}

Předchozí příklad ukazuje, jak infrastruktura schopností umožňuje výkonný mechanismus pro komunikaci schopností mezi komponentami zapojenými do testovací relace. I když ukázka demonstruje schopnost speciálně navrženou pro testovací architekturu, každá komponenta může vystavit a implementovat rozšíření, která dědí z ICapability.

Je zřejmé, že ne všechny podrobnosti lze komunikovat prostřednictvím rozhraní. Vzhledem k předchozímu příkladu, co by mělo rozšíření očekávat, jestliže je podpora CanProvidePerTestCpuConsumption zahrnuta? Jaký druh vlastních informací se očekává, že se budou přenášet prostřednictvím testovací architektury IMessageBus? Řešením je dokumentace schopnosti pro. Je odpovědností za schopnost vlastníka navrhnout, odeslat a zdokumentovat co nejjasněji implementátory, kteří chtějí efektivně spolupracovat s rozšířením, které vyžaduje konkrétní schopnost.

Rozšíření TRX reportu například umožňuje testovacímu rámci implementovat nezbytnou schopnost k přesnému generování TRX reportu. Rozšíření určené k registraci je součástí balíčku NuGet https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReport, ale možnost jej implementovat se nachází v balíčku obsahujícím pouze kontrakt.

Na závěr si shrneme hlavní aspekty systému schopností:

  • Je nezbytné usnadnit jasnou a stabilní komunikaci mezi součástmi.
  • Všechny schopnosti by měly dědit z ICapability nebo z rozhraní, které z něj dědí, a měly by být zpřístupněny prostřednictvím kolekce s rozhraním ICapabilities.
  • Pomáhá při vývoji funkcí, aniž by způsobovala zásadní změny. Pokud určitá funkce není podporovaná, je možné provést příslušnou akci.
  • Odpovědnost za návrh, expedici a dokumentaci použití funkce náleží vlastníku schopnosti . MTP může také vlastnit funkci stejným způsobem jako jakékoli jiné rozšíření.

Možnosti rámce

Platforma zveřejňuje specializované rozhraní s názvem ITestFrameworkCapability, které je základem všech funkcí vystavených pro testovací architektury. Tyto funkce jsou k dispozici při registraci testovacího frameworku na platformě.

IBannerMessageOwnerCapability

Volitelná funkce testovací architektury umožňuje testovacímu rozhraní poskytnout bannerovou zprávu platformě. Pokud je zpráva null nebo daná funkce není k dispozici, platforma použije výchozí zprávu v banneru.

Tato implementace schopností umožňuje abstrahovat různé podmínky, které může testovací architektura zvážit při rozhodování, zda by se měla zobrazit bannerová zpráva nebo ne.

Platforma zpřístupňuje službu IPlatformInformation, aby poskytla některé informace o platformě, které by mohly být užitečné při vytváření vlastní bannerové zprávy.

ITrxReportCapability

Pokud chcete poskytnout metadata specifická pro framework rozšíření sestav TRX, implementujte Microsoft.Testing.Extensions.TrxReport.Abstractions.ITrxReportCapability. Přidejte odkaz na balíček Microsoft.Testing.Extensions.TrxReport.Abstractions ze svého frameworku. Testovací aplikace také potřebuje balíček Microsoft.Testing.Extensions.TrxReport pro vytváření sestav.

Tato funkce odděluje podporu od aktivace:

  • Vraťte true z IsSupported, když váš framework může poskytovat metadata TRX.
  • V Enable() zaznamenejte, že reportér TRX požadoval metadata. Reporter volá tuto metodu na začátku testovací relace, pokud jsou povoleny sestavy TRX.
  • Po aktivaci přidejte vlastnosti TRX do testovacích uzlů, které váš framework publikuje.

Následující funkce ukládá stav aktivace. Ukázkové projekty cílí na .NET 10 a odkazují na MTP 2.5.1:

internal sealed class TrxCapability : ITrxReportCapability
{
    public bool IsSupported => true;
    public bool IsEnabled { get; private set; }

    public void Enable() => IsEnabled = true;
}
Friend NotInheritable Class TrxCapability
    Implements ITrxReportCapability

    Public ReadOnly Property IsSupported As Boolean Implements ITrxReportCapability.IsSupported
        Get
            Return True
        End Get
    End Property

    Public Property IsEnabled As Boolean
        Get
            Return _isEnabled
        End Get
        Private Set(value As Boolean)
            _isEnabled = value
        End Set
    End Property

    Private _isEnabled As Boolean

    Public Sub Enable() Implements ITrxReportCapability.Enable
        IsEnabled = True
    End Sub
End Class

Vraťte schopnost z capabilitiesFactory, kterou předáte do RegisterTestFramework. Dejte frameworku stejnou instanci capability, aby mohl sledovat Enable(). Pro ručně složenou testovací aplikaci zaregistrujte poskytovatele TRX za svým frameworkem a dalšími rozšířeními:

var trxCapability = new TrxCapability();
var builder = await TestApplication.CreateBuilderAsync(args);
builder.RegisterTestFramework(
    _ => new TestFrameworkCapabilities(trxCapability),
    (_, _) => new ReportFramework(trxCapability));
builder.AddTrxReportProvider();
Dim trxCapability As New TrxCapability()
Dim builder = Await TestApplication.CreateBuilderAsync(args)
builder.RegisterTestFramework(
    Function(services) New TestFrameworkCapabilities(trxCapability),
    Function(capabilities, services) New ReportFramework(trxCapability))
builder.AddTrxReportProvider()

Balíček abstrakce poskytuje typované vlastnosti pro TestNode.Properties:

Property Purpose
TrxFullyQualifiedTypeNameProperty Poskytuje plně kvalifikovaný název testovací třídy.
TrxCategoriesProperty Poskytuje kategorie testu.
TrxExceptionProperty Poskytuje zprávu o selhání a výpis zásobníku.
TrxMessagesProperty Obsahuje položky StandardOutputTrxMessage, StandardErrorTrxMessage a DebugOrTraceTrxMessage.
TrxTestDefinitionName Přepíše název definice testu v sestavě.
TrxWorkItemsProperty Poskytuje identifikátory pracovních položek.

Můžete například rozšířit výsledek poté, co vaše architektura určí výsledek testu:

if (trxCapability.IsEnabled)
{
    testNode.Properties.Add(
        new TrxFullyQualifiedTypeNameProperty("Contoso.CalculatorTests"));
    testNode.Properties.Add(new TrxCategoriesProperty(["Unit"]));
    testNode.Properties.Add(new TrxMessagesProperty(
        [new StandardOutputTrxMessage($"Captured output for {test.Name}.")]));
    if (failure is not null)
    {
        testNode.Properties.Add(
            new TrxExceptionProperty(failure.Message, failure.StackTrace));
    }
}
If _trxCapability.IsEnabled Then
    testNode.Properties.Add(
        New TrxFullyQualifiedTypeNameProperty("Contoso.CalculatorTests"))
    testNode.Properties.Add(New TrxCategoriesProperty({"Unit"}))
    testNode.Properties.Add(New TrxMessagesProperty(
        {New StandardOutputTrxMessage($"Captured output for {test.Name}.")}))
    If failure IsNot Nothing Then
        testNode.Properties.Add(
            New TrxExceptionProperty(failure.Message, failure.StackTrace))
    End If
End If

Tyto vlastnosti doplňují požadovaný stav testovacího uzlu; nenahrazují jej. Zprávy specifické pro TRX také nenahrazují prvky platformy StandardOutputProperty a StandardErrorProperty.

Kompletní ukázka obsahuje jeden úspěšný test a jeden úmyslně neúspěšný test. Zapíše --report-trxvýsledky i rozšířená metadata do souboru TRX a vrátí ukončovací kód 2. Pokud chcete spustit pouze test, který prošel, přidejte --filter-uid trx.pass.

Pokud tato funkce chybí nebo IsSupported je false, reporter TRX varuje, že framework nepodporuje obohacení TRX. Reporter může stále vytvořit sestavu z dostupných dat, ale podrobnosti specifické pro framework můžou chybět. Neinzerujte podporu, pokud vaše architektura neobsahuje odpovídající metadata.

IGracefulStopTestExecutionCapability

Chcete-li podporovat --maximum-failed-tests ve vlastní testovací architektuře, implementujte Microsoft.Testing.Platform.Capabilities.TestFramework.IGracefulStopTestExecutionCapability. Funkce je součástí balíčku Microsoft.Testing.Platform a je k dispozici od MTP 1.5. Autoři testů, kteří používají architekturu, která už tuto možnost podporuje, nemusí tuto funkci implementovat.

Rozhraní definuje Task StopTestExecutionAsync(CancellationToken cancellationToken). Když počet selhání dosáhne požadovaného maxima, MTP zavolá tuto metodu. Vaše implementace musí frameworku sdělit, aby přestal plánovat nové testy, a zároveň umožní testům, které již byly spuštěny, dokončit se, spustit vyčištění a publikovat jejich výsledky.

Important

Funkce a AddMaximumFailedTestsService pomocná rutina jsou experimentální rozhraní API, která generují diagnostické zprávy kompilátoru TPEXP. Jejich smlouvy mohou být změněny nebo odstraněny. Ukázkové projekty explicitně potlačují TPEXP.

Při implementaci funkce postupujte podle těchto požadavků:

  • Sdílejte stav zastavení mezi funkcí a plánovačem testů frameworku. Pouhé vrácení dokončeného úkolu nezastaví testy.
  • Zajistěte, aby požadavky na zastavení byly bezpečné pro více vláken a idempotentní. Zastavení může požadovat více než jedna komponenta platformy.
  • Vraťte se poté, co dáte znamení k zastavení. Nečekejte na celé spuštění ani na dokončení sběrnice zpráv: MTP může metodu volat, zatímco zpracovává výsledek testu, takže toto čekání může způsobit deadlock.
  • Udržujte stav řádného zastavení odděleně od zrušení žádosti. Neukončíte proces ani nezrušíte publikování výsledků, abyste implementovali řádné zastavení. Pokud vaše operace zastavení vyžaduje asynchronní práci, respektujte token zrušení metody.
  • Po dokončení aktivních testů dokončete normální životní cyklus požadavku, včetně publikování výsledků, vyčištění a volání ExecuteRequestContext.Complete().

Následující implementace používá příznak bezpečný pro přístup z více vláken. V rámci frameworku zkontrolujte IsStopRequested, než naplánujete každý test, a přestaňte přijímat novou práci, když je příznak true.

public sealed class GracefulStopCapability : IGracefulStopTestExecutionCapability
{
    private int _stopRequested;

    public bool IsStopRequested => Volatile.Read(ref _stopRequested) != 0;

    public Task StopTestExecutionAsync(CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
        Interlocked.Exchange(ref _stopRequested, 1);
        return Task.CompletedTask;
    }
}
Public NotInheritable Class GracefulStopCapability
    Implements IGracefulStopTestExecutionCapability

    Private _stopRequested As Integer

    Public ReadOnly Property IsStopRequested As Boolean
        Get
            Return Volatile.Read(_stopRequested) <> 0
        End Get
    End Property

    Public Function StopTestExecutionAsync(cancellationToken As CancellationToken) As Task _
        Implements IGracefulStopTestExecutionCapability.StopTestExecutionAsync

        cancellationToken.ThrowIfCancellationRequested()
        Interlocked.Exchange(_stopRequested, 1)
        Return Task.CompletedTask
    End Function
End Class

Zpřístupňuje funkcionalitu prostřednictvím ITestFrameworkCapabilities.Capabilities. Příklad registrace používá kolekci TestFrameworkCapabilities MTP.

Během registrace testovacího frameworku předejte instanci registrované schopnosti do vašeho frameworku. Následující pomocná rutina přijímá továrnu frameworku a entitu IExtension, která vlastní volbu příkazového řádku. Volá také AddMaximumFailedTestsService z Microsoft.Testing.Platform.Helpers oboru názvů pro registraci --maximum-failed-tests poskytovatele voleb. Bez daného poskytovatele MTP možnost nerozpozná.

public static void Register(
    ITestApplicationBuilder builder,
    IExtension owner,
    Func<GracefulStopCapability, ITestFramework> createFramework)
{
    builder.RegisterTestFramework(
        _ => new TestFrameworkCapabilities(new GracefulStopCapability()),
        (capabilities, _) => createFramework(
            capabilities.Capabilities.OfType<GracefulStopCapability>().Single()));
    builder.AddMaximumFailedTestsService(owner);
}
Public Sub Register(
    builder As ITestApplicationBuilder,
    owner As IExtension,
    createFramework As Func(Of GracefulStopCapability, ITestFramework))

    builder.RegisterTestFramework(
        Function(services) New TestFrameworkCapabilities(New GracefulStopCapability()),
        Function(capabilities, services) createFramework(
            capabilities.Capabilities.OfType(Of GracefulStopCapability)().Single()))
    builder.AddMaximumFailedTestsService(owner)
End Sub

Továrna capability vytvoří nově vytvořený stav stop a továrna frameworku načte stejnou instanci. V rámci frameworku nevytvářejte druhou odpojenou schopnost. Pro frameworky, které podporují více požadavků na spuštění, zachovejte stav zastavení v rozsahu příslušného spuštění. Při spuštění nesmažte přijatou žádost o zastavení.

MTP odmítne --maximum-failed-tests při ověřování příkazového řádku, pokud je zprostředkovatel možností zaregistrovaný, ale framework tuto funkci nezpřístupňuje. Když prahová hodnota selhání aktivuje zastavení, MTP vrátí ukončovací kód 13. Konečný počet selhání může překročit prahovou hodnotu, protože zpracování výsledků je asynchronní a testy už můžou probíhat.

Informace o kontraktu rozhraní najdete v IGracefulStopTestExecutionCapability zdroji.