Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Im Kontext von MTP bezieht sich eine Funktion auf das Potenzial, eine bestimmte Aktion auszuführen oder bestimmte Informationen bereitzustellen. Es ist ein Mittel für das Testframework und Erweiterungen, um ihre Fähigkeit bekanntzugeben, auf bestimmte Weise zu operieren oder bestimmte Informationen für die Anfragenden bereitzustellen.
Die Anforderer können jede Komponente sein, die an einer Testsitzung beteiligt ist, z. B. die Plattform, eine Erweiterung oder das Testframework selbst.
Das Hauptziel des Fähigkeitssystems besteht darin, eine effektive Kommunikation zwischen den Komponenten zu ermöglichen, die an einer Testsitzung beteiligt sind, und es ihnen zu ermöglichen, Informationen auszutauschen und ihre jeweiligen Anforderungen genau zu erfüllen.
Geführtes Beispiel
Betrachten wir ein hypothetisches Beispiel, um die Notwendigkeit eines Funktionssystems zu veranschaulichen.
Hinweis
Dieses Beispiel dient ausschließlich zu Veranschaulichungszwecken und wird derzeit nicht innerhalb von MTP oder einem Testframework implementiert.
Stellen Sie sich eine Situation vor, in der Sie eine Erweiterung haben, die erfordert, dass das Testframework nicht mehr als einen Test gleichzeitig ausführt. Darüber hinaus muss die Erweiterung nach jedem Test die CPU-Auslastung für diesen spezifischen Test kennen.
Um das vorherige Szenario zu berücksichtigen, müssen Sie sich im Testframework erkundigen, wenn:
- Es verfügt über die Möglichkeit, jeweils nur einen Test auszuführen.
- Es kann Informationen über die Menge der CPU bereitstellen, die von jedem Test verbraucht wird.
Wie kann die Erweiterung bestimmen, ob das Testframework die Möglichkeit hat, in diesem Modus zu arbeiten und CPU-Auslastungsinformationen für eine Testsitzung bereitzustellen? In MTP wird diese Funktion durch eine Implementierung der schnittstelle Microsoft.Testing.Platform.Capabilities.ICapability dargestellt:
// 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
{
}
Wie Sie sehen können, ist die ICapability Schnittstelle eine Markerschnittstelle , da sie eine beliebige Funktion darstellen kann und die tatsächliche Implementierung kontextabhängig ist. Sie werden auch das ITestFrameworkCapability beobachten, das von ICapability erbt, um die Fähigkeit zu klassifizieren. Der generische Charakter des Funktionssystems ermöglicht eine bequeme Gruppierung nach Kontext. Die ITestFrameworkCapability gruppiert alle vom Testframework implementierten Fähigkeiten. Die ICapabilities<TCapability> Schnittstelle zeigt den Satz aller Funktionen an, die von einer Erweiterung implementiert werden. Ebenso gibt es für die Basis ein kontextspezifisches Testframework namens ITestFrameworkCapabilities. Das ITestFrameworkCapabilities wird der Plattform während des Registrierungsprozesses des Testframeworks bereitgestellt.
Um eine Funktion zu erstellen, die sich auf das oben genannte Szenario bezieht, definieren Sie sie wie folgt:
public interface IDisableParallelismCapability : ITestFrameworkCapability
{
bool CanDisableParallelism { get; }
bool CanProvidePerTestCpuConsumption { get; }
void Enable();
}
Wenn das Testframework diese Schnittstelle implementiert, kann zur Laufzeit Folgendes abgefragt werden:
- Überprüfen Sie, ob das Testframework die Möglichkeit hat, Parallelität
CanDisableParallelism = truezu deaktivieren. - Ermitteln Sie, ob das Testframework CPU-Auslastungsdaten
CanProvidePerTestCPUConsumption = truebereitstellen kann. - Fordern Sie den Testadapter an, um diesen Modus zu aktivieren, indem Sie die
Enable()Methode aufrufen, bevor die Testsitzung beginnt.
Das hypothetische Codefragment in der Erweiterung könnte etwa wie folgt aussehen:
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...
}
}
Im vorherigen Beispiel wird veranschaulicht, wie die Funktionsinfrastruktur einen leistungsfähigen Mechanismus für die Kommunikation von Fähigkeiten zwischen den komponenten ermöglicht, die an einer Testsitzung beteiligt sind. Während das Beispiel eine Funktion zeigt, die speziell für das Testframework entwickelt wurde, kann jede Komponente Erweiterungen verfügbar machen und implementieren, die von ICapability erben.
Es ist offensichtlich, dass nicht alle Details über eine Schnittstelle kommuniziert werden können. Was sollte die Erweiterung in Anbetracht des vorherigen Beispiels erwarten, wenn CanProvidePerTestCpuConsumption unterstützt wird? Welche Art von benutzerdefinierten Informationen wird voraussichtlich über den IMessageBus über das Testframework übertragen? Die Lösung ist dokumentation der Funktion. Es liegt in der Verantwortung des Besitzers der Fähigkeit, sie so klar wie möglich zu entwerfen, zu versenden und zu dokumentieren, um Implementierungen zu unterstützen, die effektiv mit der Erweiterung zusammenarbeiten möchten, die die spezifische Funktion erfordert.
Beispielsweise ermöglicht die TRX-Berichtserweiterung dem Testframework die Implementierung der erforderlichen Funktion, um einen TRX-Bericht exakt zu generieren. Die Erweiterung für die Registrierung ist im https://www.nuget.org/packages/Microsoft.Testing.Extensions.TrxReportNuGet-Paket enthalten, aber die zu implementierende Funktionalität befindet sich im Paket, das nur den Vertrag enthält.
Abschließend fassen wir die wichtigsten Aspekte des Funktionssystems zusammen:
- Es ist wichtig, die klare und stabile Kommunikation zwischen Komponenten zu erleichtern.
- Alle Fähigkeiten sollten von
ICapabilityoder einer Schnittstelle, die von ICapability erbt, erben und über eine Sammlung mit derICapabilities-Schnittstelle verfügbar gemacht werden. - Sie hilft bei der Entwicklung von Features, ohne dass es zu Unterbrechungen kommt. Wenn eine bestimmte Funktion nicht unterstützt wird, können entsprechende Maßnahmen ergriffen werden.
- Die Verantwortung für das Entwerfen, Versenden und Dokumentieren der Verwendung einer Funktion liegt beim Besitzer der Funktion. MTP kann auch eine Funktion auf die gleiche Weise besitzen wie jede andere Erweiterung.
Framework-Funktionen
Die Plattform stellt eine spezielle Schnittstelle namens ITestFrameworkCapability bereit, welche die Grundlage aller Fähigkeiten bildet, die für Testframeworks zur Verfügung gestellt werden. Diese Funktionen werden beim Registrieren des Testframeworks für die Plattform bereitgestellt.
IBannerMessageOwnerCapability
Mit einer optionalen Testframeworkfunktion kann das Testframework die Bannernachricht für die Plattform bereitstellen. Wenn die Nachricht null ist oder die Funktionalität nicht vorhanden ist, verwendet die Plattform ihre Standard-Bannernachricht.
Mit dieser Funktionsimplementierung können Sie die verschiedenen Bedingungen abstrahieren, die das Testframework möglicherweise berücksichtigen muss, wenn Sie entscheiden, ob die Bannernachricht angezeigt werden soll.
Die Plattform macht den IPlatformInformation Dienst verfügbar, um einige Informationen zur Plattform bereitzustellen, die beim Erstellen Ihrer benutzerdefinierten Bannernachricht hilfreich sein könnten.
ITrxReportCapability
Um frameworkspezifische Metadaten für die TRX-Berichtserweiterung zu liefern, implementieren Sie Microsoft.Testing.Extensions.TrxReport.Abstractions.ITrxReportCapability. Verweisen Sie in Ihrem Framework auf das Paket Microsoft.Testing.Extensions.TrxReport.Abstractions. Die Testanwendung benötigt auch das Paket Microsoft.Testing.Extensions.TrxReport zum Erstellen von Berichten.
Die Funktion trennt die Unterstützung von der Aktivierung:
- Geben Sie
trueausIsSupportedzurück, wenn Ihr Framework TRX-Metadaten bereitstellen kann. - In
Enable()aufzeichnen, dass der TRX-Reporter die Metadaten angefordert hat. Der Reporter ruft diese Methode zu Beginn einer Testsitzung auf, wenn TRX-Berichte aktiviert sind. - Fügen Sie nach der Aktivierung die TRX-Eigenschaften zu den Testknoten hinzu, die Ihr Framework veröffentlicht.
Die folgende Funktion speichert den Aktivierungsstatus. Die Beispielprojekte zielen auf .NET 10 ab und verweisen auf 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
Geben Sie die Funktion aus der capabilitiesFactory zurück, die Sie an RegisterTestFramework übergeben. Weisen Sie dem Framework dieselbe Capability-Instanz zu, damit es Enable() beobachten kann. Registrieren Sie für eine manuell zusammengesetzte Testanwendung den TRX-Anbieter nach Ihrem Framework und anderen Erweiterungen:
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()
Das Abstraktionspaket stellt typisierte Eigenschaften für TestNode.Properties bereit:
| Property | Purpose |
|---|---|
TrxFullyQualifiedTypeNameProperty |
Stellt den vollqualifizierten Namen der Testklasse bereit. |
TrxCategoriesProperty |
Stellt die Kategorien des Tests bereit. |
TrxExceptionProperty |
Stellt die Fehlermeldung und den Stacktrace bereit. |
TrxMessagesProperty |
Enthält StandardOutputTrxMessage, StandardErrorTrxMessage und DebugOrTraceTrxMessage Einträge. |
TrxTestDefinitionName |
Überschreibt den Namen der Testdefinition im Bericht. |
TrxWorkItemsProperty |
Liefert Arbeitselement-IDs. |
Erweitern Sie beispielsweise ein Ergebnis, nachdem Ihr Framework das Testergebnis bestimmt hat:
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
Diese Eigenschaften ergänzen den erforderlichen Testknotenzustand; sie ersetzen sie nicht. TRX-spezifische Nachrichten ersetzen auch nicht die StandardOutputProperty und StandardErrorProperty der Plattform.
Das vollständige Beispiel enthält einen erfolgreichen Test und einen absichtlich fehlerhaften Test. Mit --report-trx schreibt es sowohl Ergebnisse als auch die erweiterten Metadaten in eine TRX-Datei und gibt dann den Exit-Code 2 zurück. Um nur den bestandenen Test auszuführen, fügen Sie --filter-uid trx.pass hinzu.
Wenn die Funktion fehlt oder IsSupported den Wert false aufweist, warnt der TRX-Reporter, dass das Framework die TRX-Anreicherung nicht unterstützt. Der Reporter kann weiterhin einen Bericht aus den verfügbaren Daten erstellen, aber rahmenspezifische Details fehlen möglicherweise. Kündigen Sie keine Unterstützung an, es sei denn, Ihr Framework stellt die entsprechenden Metadaten bereit.
IGracefulStopTestExecutionCapability
Um --maximum-failed-tests in einem benutzerdefinierten Testframework zu unterstützen, implementieren Sie Microsoft.Testing.Platform.Capabilities.TestFramework.IGracefulStopTestExecutionCapability. Die Funktion ist Teil des Pakets Microsoft.Testing.Platform und ab MTP 1.5 verfügbar. Testautoren, die ein Framework verwenden, das die Option bereits unterstützt, müssen die Funktion nicht implementieren.
Die Schnittstelle definiert Task StopTestExecutionAsync(CancellationToken cancellationToken). Wenn die Fehleranzahl das angeforderte Maximum erreicht, ruft MTP diese Methode auf. Ihre Implementierung muss das Framework anweisen, die Planung neuer Tests zu beenden, während bereits begonnene Tests abgeschlossen, Bereinigungen ausgeführt und deren Ergebnisse veröffentlicht werden können.
Important
Die Funktion und das Hilfsprogramm AddMaximumFailedTestsService sind experimentelle APIs, die die Compilerdiagnose TPEXP erzeugen. Ihre Verträge können geändert oder entfernt werden. Die Beispielprojekte unterdrücken TPEXP explizit.
Beachten Sie bei der Implementierung der Funktion die folgenden Anforderungen:
- Geben Sie den Stoppzustand zwischen der Funktion und dem Testplaner des Frameworks frei. Das bloße Zurückgeben einer abgeschlossenen Aufgabe stoppt keine Tests.
- Konfigurieren Sie Stoppanforderungen threadsicher und idempotent. Mehrere Plattformkomponenten können einen Stopp anfordern.
- Geben Sie die Steuerung zurück, nachdem Sie den Stopp signalisiert haben. Warten Sie nicht, bis die gesamte Ausführung abgeschlossen ist oder der Nachrichtenbus abgeschlossen ist: MTP kann die Methode aufrufen, während es ein Testergebnis verarbeitet, sodass dieses Warten zu einem Deadlock führen kann.
- Halten Sie den Zustand für das ordnungsgemäße Beenden von der Anforderungsstornierung getrennt. Beenden Sie den Prozess nicht und brechen Sie die Ergebnisveröffentlichung nicht ab, um einen ordnungsgemäßen Stopp zu implementieren. Berücksichtigen Sie das Abbruchtoken der Methode, wenn ihr Stoppvorgang asynchrone Arbeit erfordert.
- Schließen Sie nach Abschluss der aktiven Tests den normalen Anforderungslebenszyklus ab, einschließlich Ergebnisveröffentlichung, Bereinigung und aufruf von
ExecuteRequestContext.Complete().
Die folgende Implementierung verwendet ein threadsicheres Flag. Überprüfen Sie in Ihrem Framework IsStopRequested, bevor Sie den jeweiligen Test planen, und nehmen Sie keine weiteren neuen Aufgaben an, wenn das Flag true ist.
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
Stellen Sie die Funktionalität über ITestFrameworkCapabilities.Capabilities bereit. Im Registrierungsbeispiel wird die TestFrameworkCapabilities MTP-Auflistung verwendet.
Übergeben Sie während der Registrierung des Testframeworks die registrierte Capability-Instanz an Ihr Framework. Das folgende Hilfsprogramm akzeptiert Ihre Framework-Factory und eine IExtension, die die Befehlszeilenoption besitzt. Außerdem wird Microsoft.Testing.Platform.Helpers aus dem Namespace AddMaximumFailedTestsService aufgerufen, um den --maximum-failed-tests-Optionsanbieter zu registrieren. Ohne diesen Anbieter erkennt MTP die Option nicht.
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
Die Funktions-Factory erstellt einen neuen Stoppzustand, und die Framework-Factory ruft dieselbe Instanz ab. Erstellen Sie keine zweite, getrennte Funktion in Ihrem Framework. Für Frameworks, die mehrere Ausführungsanforderungen unterstützen, halten Sie den Stoppstatus auf die entsprechende Ausführung beschränkt. Löschen Sie beim Starten der Ausführung keine akzeptierte Stoppanforderung.
MTP weist --maximum-failed-tests während der Befehlszeilenüberprüfung zurück, wenn der Optionsanbieter registriert ist, aber das Framework diese Funktion nicht verfügbar macht. Wenn der Fehlerschwellenwert einen Stopp auslöst, gibt MTP den Ausgangscode 13zurück. Die endgültige Fehleranzahl kann den Schwellenwert überschreiten, da die Ergebnisverarbeitung asynchron ist und Tests möglicherweise bereits laufen.
Informationen zum Schnittstellenvertrag finden Sie in der IGracefulStopTestExecutionCapabilityQuelle.