Freigeben über


Testen der Ausführung und Kontrolle in MSTest

MSTest stellt Attribute bereit, um zu steuern, wie Tests ausgeführt werden, einschließlich Parallelisierung, Threadingmodelle, Timeouts, Wiederholungen und bedingter Ausführung basierend auf Plattform oder Umgebung.

Threadingattribute

Threadingattribute steuern, welche Threadmodelltestmethoden verwendet werden. Diese Attribute sind wichtig, wenn COM-Komponenten, UI-Elemente oder Code mit bestimmten Threadinganforderungen getestet werden.

STATestClassAttribute

Führt STATestClassAttribute alle Testmethoden in einer Klasse aus (einschließlich ClassInitialize und ClassCleanup) in einem Einzel-Thread-Apartment (STA). Verwenden Sie dieses Attribut beim Testen von COM-Objekten, die STA erfordern.

[STATestClass]
public class ComInteropTests
{
    [TestMethod]
    public void TestComComponent()
    {
        // This test runs in an STA thread
        var comObject = new SomeComObject();
        // Test COM interactions
    }
}

Hinweis

Dieses Attribut wird nur unter Windows in MSTest v3.6 und höher unterstützt.

STATestMethodAttribute

Die STATestMethodAttribute führt eine spezifische Testmethode in einem Single-Threaded Apartment aus. Verwenden Sie dieses Attribut für einzelne Tests, die STA benötigen, während andere Tests in der Klasse nicht vorhanden sind.

[TestClass]
public class MixedThreadingTests
{
    [STATestMethod]
    public void TestRequiringSTA()
    {
        // This test runs in an STA thread
    }

    [TestMethod]
    public void RegularTest()
    {
        // This test uses default threading
    }
}

Hinweis

Dieses Attribut wird nur unter Windows in MSTest v3.6 und höher unterstützt.

Beibehalten des STA-Kontexts für asynchrone Fortsetzungen

Ab MSTest 4.1 enthält die STATestMethodAttribute Eigenschaft eine UseSTASynchronizationContext Eigenschaft, die sicherstellt, dass asynchrone Fortsetzungen im selben STA-Thread ausgeführt werden. Wenn diese Option aktiviert ist, erstellt das Attribut einen benutzerdefinierten Code SynchronizationContext , der Fortsetzungen zurück an den STA-Thread sendet, was für das Testen von UI-Komponenten, die STA-Threading während ihrer asynchronen Vorgänge erfordern, unerlässlich ist.

[TestClass]
public class UIComponentTests
{
    [STATestMethod(UseSTASynchronizationContext = true)]
    public async Task TestAsyncUIOperation()
    {
        // Initial code runs on STA thread
        var control = new MyControl();
        
        await control.LoadDataAsync();
        
        // Continuation also runs on STA thread,
        // ensuring UI operations remain valid
        Assert.IsTrue(control.IsDataLoaded);
    }
}

Tipp

Wird UseSTASynchronizationContext = true beim Testen von Windows Forms- oder WPF-Komponenten verwendet, die asynchrone Vorgänge ausführen und erwarten, dass ihre Fortsetzungen im selben Thread ausgeführt werden.

UITestMethodAttribute

Das UITestMethod Attribut plant die Testausführung im UI-Thread. Dieses Attribut wurde für das Testen von UWP- und WinUI-Anwendungen entwickelt, die UI-Threadzugriff erfordern.

[TestClass]
public class WinUITests
{
    [UITestMethod]
    public void TestUIComponent()
    {
        // This test runs on the UI thread
        var button = new Button();
        button.Content = "Click me";
        Assert.IsNotNull(button.Content);
    }
}

Hinweis

Für dieses Attribut ist der entsprechende MSTest-Adapter für UWP- oder WinUI-Plattformen erforderlich. Weitere Informationen finden Sie im Abschnitt zum Plattformsupport .

Parallelisierungsattribute

Parallelisierungsattribute steuern, ob und wie Tests gleichzeitig ausgeführt werden, wodurch die Testausführungszeit verbessert wird.

ParallelizeAttribute

Standardmäßig führt MSTest Tests sequenziell aus. Das ParallelizeAttribute Attribut auf Assemblyebene ermöglicht die parallele Testausführung.

using Microsoft.VisualStudio.TestTools.UnitTesting;

[assembly: Parallelize(Workers = 0, Scope = ExecutionScope.MethodLevel)]

Parallelisierungsbereich

Geltungsbereich Verhalten
ClassLevel Mehrere Testklassen werden parallel ausgeführt, aber Tests innerhalb einer Klasse werden sequenziell ausgeführt.
MethodLevel Einzelne Testmethoden können unabhängig von ihrer Klasse parallel ausgeführt werden.

Arbeitsthreads

Die Workers Eigenschaft gibt die maximale Anzahl von Threads für die parallele Ausführung an:

  • 0 (Standard): Verwenden Sie die Anzahl der logischen Prozessoren auf dem Computer.
  • Eine beliebige positive ganze Zahl: Verwenden Sie diese bestimmte Anzahl von Threads.
// Parallelize at class level with 2 worker threads
[assembly: Parallelize(Workers = 2, Scope = ExecutionScope.ClassLevel)]

Tipp

Sie können die Parallelisierung auch über Runsettings oder testconfig.json konfigurieren, ohne Code zu ändern.

Tipp

Aktivieren Sie die Parallelisierung standardmäßig auf Assemblyebene, auch wenn viele Tests derzeit eine sequenzielle Ausführung erfordern. Dieser Ansatz empfiehlt das Schreiben neuer Tests, die die parallele Ausführung von Anfang an unterstützen. Verwenden Sie den MSTEST0001 Analyzer, um sicherzustellen, dass jede Testklasse explizit ihre Parallelisierungsabsicht deklariert, wodurch Sie überprüfen müssen, ob jede Klasse die gleichzeitige Ausführung sicher unterstützt. Häufig reicht das Ausschließen von nur wenigen Klassen oder Methoden DoNotParallelize aus, sodass die meisten Tests parallel ausgeführt werden können, um die Testausführung erheblich zu beschleunigen.

DoNotParallelizeAttribute

Die DoNotParallelizeAttribute verhindert die parallele Ausführung bestimmter Assemblys, Klassen oder Methoden. Verwenden Sie dieses Attribut, wenn Tests einen Status oder Ressourcen teilen, auf die nicht sicher gleichzeitig zugegriffen werden kann.

[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]

[TestClass]
public class ParallelTests
{
    [TestMethod]
    public void CanRunInParallel()
    {
        // This test can run with others
    }
}

[TestClass]
[DoNotParallelize]
public class SequentialTests
{
    [TestMethod]
    public void MustRunSequentially()
    {
        // This class's tests run sequentially
    }
}

[TestClass]
public class MixedTests
{
    [TestMethod]
    public void CanRunInParallel()
    {
        // This test can run with others
    }

    [TestMethod]
    [DoNotParallelize]
    public void MustBeIsolated()
    {
        // This specific test doesn't run in parallel
    }
}

Hinweis

Sie benötigen DoNotParallelize nur, wenn Sie die parallele Ausführung mit dem Parallelize Attribut aktiviert haben.

Timeoutattribute

Timeout-Attribute verhindern, dass Tests unbegrenzt ausgeführt werden, und helfen, Leistungsprobleme zu identifizieren.

TimeoutAttribute

Der TimeoutAttribute gibt die maximale Zeit (in Millisekunden) an, die eine Test- oder Vorrichtungsmethode ausführen kann. Wenn die Ausführung diese Zeit überschreitet, schlägt der Test fehl.

[TestClass]
public class TimeoutTests
{
    [TestMethod]
    [Timeout(5000)] // 5 seconds
    public void TestWithTimeout()
    {
        // Test must complete within 5 seconds
    }
}

Tipp

Sie können ein globales Testtimeout über Runsettings (TestTimeout) oder testconfig.json (timeout.test) konfigurieren, ohne Code zu ändern.

Anwenden von Timeout auf Vorrichtungsmethoden

Sie können timeouts auch auf Initialisierungs- und Bereinigungsmethoden anwenden:

[TestClass]
public class FixtureTimeoutTests
{
    [ClassInitialize]
    [Timeout(10000)]
    public static void ClassInit(TestContext context)
    {
        // Must complete within 10 seconds
    }

    [TestInitialize]
    [Timeout(2000)]
    public void TestInit()
    {
        // Must complete within 2 seconds
    }
}

Tipp

Jede Einrichtungsmethode, die ein [Timeout] Attribut akzeptiert, verfügt über eine entsprechende globale Konfigurationseinstellung. Konfigurieren Sie Timeouts global über Runsettings oder testconfig.json mithilfe von Einstellungen wie TestInitializeTimeout, ClassInitializeTimeout, AssemblyInitializeTimeout und deren Bereinigungs-Entsprechungen.

Hinweis

Timeouts sind nicht unbedingt hundertprozentig genau. Der Test wird nach Ablauf der angegebenen Zeit abgebrochen, der tatsächliche Abbruch kann jedoch etwas länger dauern.

Kooperative Stornierung

Standardmäßig umschließt MSTest jede zeitlich festgelegte Testmethode in einer separaten Aufgabe oder einem separaten Thread. Wenn das Timeout erreicht ist, beendet das Framework die Beobachtung des Tests, aber die zugrunde liegende Aufgabe wird weiterhin im Hintergrund ausgeführt. Dieses Verhalten kann Probleme verursachen:

  • Die Testmethode greift auch nach dem Timeout weiterhin auf Ressourcen zu und mutiert den Zustand.
  • Die Hintergrundausführung kann zu Rennbedingungen führen, die sich auf nachfolgende Tests auswirken.
  • Bei jeder Timed-Methode fällt zusätzlicher Aufwand durch den Task-/Thread-Wrapper an.

Verwenden Sie ab MSTest 3.6 die CooperativeCancellation Eigenschaft, um diese Probleme zu vermeiden. Im kooperativen Modus schließt MSTest Ihren Test nicht in eine zusätzliche Aufgabe um. Wenn das Timeout erreicht ist, signalisiert das Framework stattdessen das Abbruchtoken. Ihr Testcode ist dafür verantwortlich, das Token regelmäßig zu überprüfen und ordnungsgemäß zu beenden.

[TestClass]
public class CooperativeTimeoutTests
{
    [TestMethod]
    [Timeout(5000, CooperativeCancellation = true)]
    public async Task TestWithCooperativeCancellation(CancellationToken cancellationToken)
    {
        // Check the token periodically
        while (!cancellationToken.IsCancellationRequested)
        {
            await Task.Delay(100, cancellationToken);
            // Do work
        }
    }

    [TestMethod]
    [Timeout(5000, CooperativeCancellation = true)]
    public void SyncTestWithCooperativeCancellation(CancellationToken cancellationToken)
    {
        // Works with sync methods too
        for (int i = 0; i < 1000; i++)
        {
            cancellationToken.ThrowIfCancellationRequested();
            // Do work
        }
    }
}

Vorteile der kooperativen Stornierung:

  • Geringerer Performance-Overhead (kein zusätzlicher Task-/Thread-Wrapper pro Test).
  • Effizienteres Bereinigen von Ressourcen, da Ihr Code den Abbruch explizit verarbeitet.
  • Richtet sich an standardmäßigen .NET-Abbruchmustern.
  • Deterministisches Verhalten durch Vermeidung von Wettlaufsituationen zwischen Testcode und nicht überwachter Hintergrundausführung.

Hinweis

Kooperativer Abbruch erfordert, dass Ihr Testcode das Abbruchtoken regelmäßig überprüft. Wenn Ihr Code das Token nicht überprüft, wird der Test nicht beendet, wenn timeout erreicht ist.

Tipp

Sie können den kooperativen Abbruch global für alle Timeoutattribute über Runsettings oder testconfig.json aktivieren, anstatt sie für jedes Attribut einzeln festzulegen.

Tipp

Verwandte Analysegeräte:

  • MSTEST0045 – empfiehlt die Verwendung kooperativer Abbruchvorgänge für Timeoutattribute.

Wiederholen von Attributen

Wiederholungsattribute helfen bei der Behandlung von flackerigen Tests, indem automatisch fehlgeschlagene Tests erneut ausgeführt werden.

RetryAttribute

Die RetryAttribute, eingeführt in MSTest 3.8, wiederholt automatisch Testmethoden, die fehlschlagen oder auslaufen. Konfigurieren Sie die maximalen Wiederholungsversuche, die Verzögerung zwischen den Wiederholungsversuchen und die Backoff-Strategie.

[TestClass]
public class RetryTests
{
    [TestMethod]
    [Retry(3)] // Retry up to 3 times if the test fails
    public void FlakeyNetworkTest()
    {
        // Test that might occasionally fail due to network issues
    }

    [TestMethod]
    [Retry(3, MillisecondsDelayBetweenRetries = 1000, BackoffType = DelayBackoffType.Exponential)]
    public void TestWithExponentialBackoff()
    {
        // Retries with increasing delays: 1s, 2s, 4s
    }

    [TestMethod]
    [Retry(5, MillisecondsDelayBetweenRetries = 500, BackoffType = DelayBackoffType.Constant)]
    public void TestWithConstantDelay()
    {
        // Retries with constant 500ms delay between attempts
    }
}

Konfigurationsoptionen

Eigentum Description Standard
MaxRetryAttempts Maximale Anzahl der Wiederholungsversuche (schreibgeschützt, im Konstruktor festgelegt) Erforderlich
MillisecondsDelayBetweenRetries Basisverzögerung zwischen Wiederholungen (in ms) 0
BackoffType Constant oder Exponential Verzögerung Constant

Hinweis

Nur ein RetryAttribute kann pro Testmethode vorhanden sein. Sie können nicht für Methoden verwenden RetryAttribute , die nicht mit TestMethodmarkiert sind.

Tipp

Verwandte Analysegeräte:

  • MSTEST0043 – empfiehlt, RetryAttribute bei Testmethoden zu verwenden.

Benutzerdefinierte Wiederholungsimplementierungen

Erstellen Sie benutzerdefinierte Wiederholungslogik, indem Sie von RetryBaseAttribute:

public class CustomRetryAttribute : RetryBaseAttribute
{
    private readonly int _maxRetries;

    public CustomRetryAttribute(int maxRetries)
    {
        _maxRetries = maxRetries;
    }

    // Implement abstract members
    // Add custom logic for retry conditions
}

Attribute für die bedingte Ausführung

Bedingte Ausführungsattribute steuern, ob Tests basierend auf bestimmten Bedingungen wie Betriebssystem oder CI-Umgebung ausgeführt werden.

ConditionBaseAttribute

Dies ConditionBaseAttribute ist die abstrakte Basisklasse für die bedingte Ausführung. MSTest bietet mehrere integrierte Implementierungen.

Hinweis

Bedingungsattribute werden standardmäßig nicht geerbt. Das Anwenden auf eine Basisklasse wirkt sich nicht auf abgeleitete Klassen aus. Benutzerdefinierte Bedingungsattribute können dieses Verhalten durch Neudefinieren von AttributeUsage überschreiben, aber es wird nicht empfohlen, um die Konsistenz mit den integrierten Bedingungsattributen zu wahren.

Tipp

Verwandte Analysegeräte:

  • MSTEST0041 – empfiehlt die Verwendung bedingungsbasierter Attribute mit Testklassen.

OSConditionAttribute

Die OSConditionAttribute führt die Tests basierend auf dem Betriebssystem aus oder überspringt sie. Verwenden Sie das OperatingSystems Flags-Enum, um anzugeben, welche Betriebssysteme gelten.

[TestClass]
public class OSSpecificTests
{
    [TestMethod]
    [OSCondition(OperatingSystems.Windows)]
    public void WindowsOnlyTest()
    {
        // Runs only on Windows
    }

    [TestMethod]
    [OSCondition(OperatingSystems.Linux | OperatingSystems.OSX)]
    public void UnixLikeOnlyTest()
    {
        // Runs on Linux or macOS
    }

    [TestMethod]
    [OSCondition(ConditionMode.Exclude, OperatingSystems.Windows)]
    public void SkipOnWindowsTest()
    {
        // Runs on any OS except Windows
    }
}

Unterstützte Betriebssysteme

OS Description
Windows Microsoft Windows
Linux Linux-Verteilungen
OSX macOS
FreeBSD FreeBSD

Kombinieren Sie Betriebssysteme mit dem bitweisen OR-Operator (|).

Tipp

Verwandte Analysegeräte:

  • MSTEST0061 – empfiehlt die Verwendung des OSCondition-Attributs anstelle von Laufzeitüberprüfungen.

CIConditionAttribute

Die CIConditionAttribute Tests werden ausgeführt oder übersprungen, je nachdem, ob sie in einer kontinuierlichen Integrationsumgebung ausgeführt werden.

[TestClass]
public class CIAwareTests
{
    [TestMethod]
    [CICondition] // Default: runs only in CI
    public void CIOnlyTest()
    {
        // Runs only in CI environments
    }

    [TestMethod]
    [CICondition(ConditionMode.Include)]
    public void ExplicitCIOnlyTest()
    {
        // Same as above, explicitly stated
    }

    [TestMethod]
    [CICondition(ConditionMode.Exclude)]
    public void LocalDevelopmentOnlyTest()
    {
        // Skipped in CI, runs during local development
    }
}

IgnoreAttribute

Die IgnoreAttribute überspringt bedingungslos eine Testklasse oder -methode. Geben Sie optional einen Grund für das Ignorieren an.

Tipp

Verwandte Analyse: MSTEST0015 - Testmethode sollte nicht ignoriert werden. Aktivieren Sie diesen Analyzer, um Tests zu erkennen, die dauerhaft ignoriert werden.

[TestClass]
public class IgnoreExamples
{
    [TestMethod]
    [Ignore]
    public void TemporarilyDisabled()
    {
        // This test is skipped
    }

    [TestMethod]
    [Ignore("Waiting for bug #123 to be fixed")]
    public void DisabledWithReason()
    {
        // This test is skipped with a documented reason
    }
}

[TestClass]
[Ignore("Entire class needs refactoring")]
public class IgnoredTestClass
{
    [TestMethod]
    public void Test1() { }  // Skipped

    [TestMethod]
    public void Test2() { }  // Skipped
}

Wenn Tests aufgrund bekannter Probleme ignoriert werden, verwenden WorkItemAttribute Oder GitHubWorkItemAttribute zur Rückverfolgbarkeit:

[TestClass]
public class TrackedIgnoreExamples
{
    [TestMethod]
    [Ignore("Waiting for fix")]
    [WorkItem(12345)]
    public void TestWithWorkItem()
    {
        // Linked to work item 12345
    }

    [TestMethod]
    [Ignore("Known issue")]
    [GitHubWorkItem("https://github.com/owner/repo/issues/42")]
    public void TestWithGitHubIssue()
    {
        // Linked to GitHub issue #42
    }
}

Bewährte Methoden

  1. Verwenden Sie Parallelisierung weise: Aktivieren Sie die Parallelisierung für unabhängige Tests, verwenden Sie DoNotParallelize sie jedoch für Tests, die den Status teilen.

  2. Legen Sie geeignete Timeouts fest: Wählen Sie Timeouts aus, die die normale Ausführung zulassen, aber hängengebliebene Tests erkennen. Erwägen Sie langsame CI-Umgebungen.

  3. Verwenden Sie den kooperativen Abbruch, um den Aufwand zusätzlicher Aufgabenwrapper zu vermeiden und die Ausführung von Timeouttests im Hintergrund zu verhindern. Aktivieren Sie die MSTEST0045 Analyzer, um diese Vorgehensweise zu erzwingen.

  4. Dokument ignorierte Tests: Geben Sie beim Ignorieren von Tests immer einen Grund und einen Arbeitselementverweis an.

  5. Verwenden Sie Wiederholungsversuche sparsam: Beheben Sie die Ursache von flackernden Tests, anstatt sich auf Wiederholungen zu verlassen.

  6. Testen Sie betriebssystemspezifischen Code entsprechend: Verwenden Sie diese Anwendung OSCondition , um plattformspezifische Tests nur dann auszuführen, wenn sie anwendbar sind.

Siehe auch