Testování spouštění a řízení v MSTestu

MSTest poskytuje atributy pro řízení spouštění testů, včetně paralelizace, modelů vláken, vypršení časových limitů, opakování a podmíněného spouštění na základě platformy nebo prostředí.

Atributy threadingu

Atributy vláken určují, které metody testování modelu vláken používají. Tyto atributy jsou nezbytné při testování komponent modelu COM, prvků uživatelského rozhraní nebo kódu s konkrétními požadavky na podprocesy.

STATestClassAttribute

Spustí STATestClassAttribute všechny testovací metody ve třídě (včetně ClassInitialize a ClassCleanup) v jednovláknovém bytě (STA). Tento atribut použijte při testování objektů MODELU COM, které vyžadují STA.

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

Poznámka:

Tento atribut je podporován pouze ve Windows v MSTest v3.6 a novější.

STATestMethodAttribute

Spustí STATestMethodAttribute konkrétní testovací metodu v jednovláknovém apartmánu. Tento atribut použijte pro jednotlivé testy, které potřebují STA, zatímco jiné testy ve třídě ne.

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

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

Poznámka:

Tento atribut je podporován pouze ve Windows v MSTest v3.6 a novější.

Zachování kontextu STA pro asynchronní pokračování

Počínaje MSTest 4.1 STATestMethodAttribute obsahuje UseSTASynchronizationContext vlastnost, která zajišťuje, že asynchronní pokračování běží na stejném vlákně STA. Pokud je tato možnost povolená, vytvoří atribut vlastní, SynchronizationContext který publikuje pokračování zpět do vlákna STA, což je nezbytné pro testování komponent uživatelského rozhraní, které vyžadují vlákno STA v rámci jejich asynchronních operací.

[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);
    }
}

Návod

Používá se UseSTASynchronizationContext = true při testování komponent model Windows Forms nebo WPF (Windows Presentation Foundation), které provádějí asynchronní operace a očekávají, že jejich pokračování poběží ve stejném vlákně.

UITestMethodAttribute

Atribut UITestMethod naplánuje spuštění testu ve vlákně uživatelského rozhraní. Tento atribut je určený pro testování aplikací UPW a WinUI, které vyžadují přístup k vláknům uživatelského rozhraní.

[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);
    }
}

Poznámka:

Tento atribut vyžaduje příslušný adaptér MSTest pro platformy UPW nebo WinUI. Další informace najdete v části podpory platformy .

Atributy paralelizace

Atributy paralelizace řídí, jestli a jak testy běží souběžně, což zlepšuje dobu provádění testů.

ParallelizeAttribute

Ve výchozím nastavení msTest spouští testy postupně. Atribut ParallelizeAttribute na úrovni sestavení umožňuje paralelní provádění testů.

using Microsoft.VisualStudio.TestTools.UnitTesting;

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

Rozsah paralelizace

Scope Chování
ClassLevel Paralelně běží více tříd testů, ale testy v rámci třídy se spouštějí postupně.
MethodLevel Jednotlivé testovací metody se můžou spouštět paralelně bez ohledu na jejich třídu.

Pracovní vlákna

Vlastnost Workers určuje maximální počet vláken pro paralelní provádění:

  • 0 (výchozí): Použijte počet logických procesorů na počítači.
  • Libovolné kladné celé číslo: Použijte konkrétní počet vláken.
// Parallelize at class level with 2 worker threads
[assembly: Parallelize(Workers = 2, Scope = ExecutionScope.ClassLevel)]

Návod

Paralelizaci můžete nakonfigurovat bez úpravy kódu pomocí runsettings, testconfig.jsonnebo MSTestParallelizeScope vlastností MSBuildMSTestParallelizeWorkers.

Návod

Ve výchozím nastavení povolte paralelizaci na úrovni sestavení, a to i v případě, že mnoho testů aktuálně vyžaduje sekvenční spuštění. Tento přístup podporuje psaní nových testů, které podporují paralelní spouštění od začátku. Pomocí analyzátoru MSTEST0001 se ujistěte, že sestavení explicitně deklaruje svůj záměr paralelizace s [assembly: Parallelize] nebo [assembly: DoNotParallelize]. Po povolení paralelizace zkontrolujte jednotlivé třídy testů a zjistěte, jestli bezpečně podporuje souběžné spouštění. Často stačí vyloučit pouze několik tříd nebo metod pomocí DoNotParallelize, což umožňuje většině testů spouštět se paralelně a výrazně tím zrychlit provádění testů.

DoNotParallelizeAttribute

DoNotParallelizeAttribute brání paralelnímu spuštění pro konkrétní sestavení, třídy nebo metody. Tento atribut použijte, když testy sdílejí stav nebo prostředky, ke kterým není možné bezpečně přistupovat současně.

[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
    }
}

Poznámka:

Potřebujete pouze DoNotParallelize, když jste povolili paralelní provádění s atributem Parallelize.

Atributy časového limitu

Atributy časového limitu brání spuštění testů na neomezenou dobu a pomáhají identifikovat problémy s výkonem.

TimeoutAttribute

Určuje TimeoutAttribute maximální dobu (v milisekundách), po které může běžet testovací nebo přípojná metoda. Pokud provádění tento čas překročí, test selže.

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

Návod

Časový limit globálního testu můžete nakonfigurovat prostřednictvím runsettings (TestTimeout) nebo testconfig.json () bezetimeout.test změny kódu.

Použití časového limitu u metod zařízení

Můžete také použít časové limity pro inicializaci a čištění metod:

[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
    }
}

Návod

Každá metoda příslušenství, která přijímá [Timeout] atribut, má ekvivalentní globální nastavení konfigurace. Konfigurujte časové limity globálně prostřednictvím runsettings nebo testconfig.json pomocí nastavení, jako je TestInitializeTimeout, ClassInitializeTimeout, AssemblyInitializeTimeout, a jejich protějšky pro vyčištění.

Poznámka:

Časové limity nejsou zaručeny jako přesné. Test po uplynutí zadaného času přeruší, ale skutečné zrušení může trvat trochu déle.

Zrušení spolupráce

Ve výchozím nastavení msTest zabalí každou časovanou testovací metodu v samostatném úkolu nebo vlákně. Po dosažení časového limitu framework přestane sledovat test, zatímco běžící úloha pokračuje na pozadí. Toto chování může způsobit problémy:

  • Testovací metoda bude nadále přistupovat k prostředkům a mutovat stav i po vypršení časového limitu.
  • Provádění na pozadí může vést k podmínkám soutěžení, které ovlivňují následné testy.
  • Každá časovaná metoda způsobuje další režii z obálky úloh nebo vláken.

Počínaje verzí MSTest 3.6 použijte CooperativeCancellation vlastnost, abyste se těmto problémům vyhnuli. V režimu spolupráce msTest nezabalí test do dodatečného úkolu. Místo toho, po uplynutí časového limitu, framework signalizuje token zrušení. Váš testovací kód zodpovídá za pravidelnou kontrolu tokenu a řádné ukončení.

[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
        }
    }
}

Výhody zrušení spolupráce:

  • Nižší režijní náklady na výkon (bez nadbytečné obálky úloh nebo vláken na test)
  • Čistší úklid prostředků, protože váš kód explicitně zpracovává zrušení.
  • Odpovídá standardním vzorům pro zrušení v .NET.
  • Deterministické chování tím, že se vyhnete podmínkám časování mezi testovacím kódem a nezarezervovaným spuštěním na pozadí.

Poznámka:

Kooperativní zrušení vyžaduje, aby váš testovací kód pravidelně kontroloval token zrušení. Pokud váš kód token nekontroluje, test se při dosažení časového limitu ve skutečnosti nezastaví.

Návod

Pro všechny atributy časového limitu můžete povolit globální zrušení spolupráce prostřednictvím runsettings nebo testconfig.json místo toho, abyste ho nastavili u každého atributu jednotlivě.

Návod

Související analyzátory:

  • MSTEST0045 – doporučuje použití kooperativního zrušení u atributů časového limitu.

Atributy opětovného pokusu

Atributy opakování pomáhají zpracovávat nesplněné testy tím, že automaticky znovu spustí neúspěšné testy.

RetryAttribute

Funkce RetryAttribute, zavedená v MSTest 3.8, automaticky opakuje testovací metody, které selžou nebo u nich vyprší časový limit. Nakonfigurujte maximální počet pokusů o opakování, zpoždění mezi opakovanými pokusy a strategii ústupu.

[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
    }
}

Možnosti konfigurace

Vlastnictví Description Výchozí
MaxRetryAttempts Maximální počet pokusů o opakování (jen pro čtení, nastavený prostřednictvím konstruktoru) Povinné
MillisecondsDelayBetweenRetries Základní prodleva mezi opakovanými pokusy (v ms) 0
BackoffType Constant nebo Exponential zpoždění Constant

Poznámka:

V testovací metodě může být přítomna pouze jedna RetryAttribute . Nemůžete použít RetryAttribute u metod, které nejsou označené TestMethod.

Poznámka:

Počínaje verzí MSTest 4.3 RetryAttribute lze použít také na úrovni testovací třídy. Při použití na testovací třídu se vztahuje na každou testovací metodu ve třídě. RetryAttribute u metody má přednost před RetryAttribute u obsahující třídy.

Návod

Související analyzátory:

  • MSTEST0043 – doporučuje se používat RetryAttribute u testovacích metod.

Vlastní implementace opakování

Od verze MSTest 3.8 vytvořte vlastní logiku opakování děděním od RetryBaseAttribute:

public class CustomRetryAttribute : RetryBaseAttribute
{
    private readonly int _maxRetries;

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

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

Atributy podmíněného spuštění

Atributy podmíněného spouštění řídí, jestli se testy spouští na základě konkrétních podmínek, jako je operační systém nebo prostředí CI.

ConditionBaseAttribute

Jedná se ConditionBaseAttribute o abstraktní základní třídu pro podmíněné spuštění. MSTest poskytuje několik předdefinovaných implementací.

Poznámka:

Tato ConditionBaseAttribute verze byla zavedena v MSTest 3.8.

Poznámka:

Ve výchozím nastavení nejsou atributy podmínky zděděny. Použití na základní třídu nemá vliv na odvozené třídy. Atributy vlastních podmínek můžou toto chování přepsat předefinováním AttributeUsage, ale toto se nedoporučuje pro udržení konzistence s vestavěnými atributy podmínek.

Návod

Související analyzátory:

  • MSTEST0041 – doporučuje používat atributy založené na podmínce s testovacími třídami.

OSConditionAttribute

Spustí OSConditionAttribute nebo přeskočí testy na základě operačního systému. Pomocí výčtových příznaků OperatingSystems určete, na které operační systémy se vztahují.

Poznámka:

Tato OSConditionAttribute verze byla zavedena v MSTest 3.8.

[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
    }
}

Podporované operační systémy

operační systém Description
Windows Microsoft Windows
Linux Linuxové distribuce
OSX macOS
FreeBSD FreeBSD

Kombinujte operační systémy pomocí bitového OR operátoru (|).

Návod

Související analyzátory:

  • MSTEST0061 – místo kontrol za běhu doporučuje používat OSCondition atribut.

CIConditionAttribute

CIConditionAttribute spouští nebo přeskočí testy podle toho, zda jsou spouštěny v prostředí kontinuální integrace.

Poznámka:

Tato CIConditionAttribute verze byla zavedena v MSTest 3.10.

[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
    }
}

MemberConditionAttribute

MemberConditionAttribute, představený v MSTest 4.3, spustí nebo přeskočí testovací třídu nebo testovací metodu na základě hodnoty jednoho nebo více statických členů bool. Na každý člen odkazuje jeho deklarující typ a název a musí být public static, return boola (pro metody) být bez parametrů. Když je zadáno několik členů, jsou spojeni logickým operátorem AND. Použijte ConditionMode k invertování podmínky.

public static class TestConditions
{
    public static bool IsFeatureEnabled => true;
}

[TestClass]
public class FeatureTests
{
    [TestMethod]
    [MemberCondition(typeof(TestConditions), nameof(TestConditions.IsFeatureEnabled))]
    public void RunsWhenFeatureEnabled()
    {
    }

    [TestMethod]
    [MemberCondition(ConditionMode.Exclude, typeof(TestConditions), nameof(TestConditions.IsFeatureEnabled))]
    public void SkippedWhenFeatureEnabled()
    {
    }
}

Návod

Související analyzátor: MSTEST0070 - [MemberCondition] argumenty by měly být platné.

ArchitectureConditionAttribute

, ArchitectureConditionAttributezavedený v MSTest 4.3, spouští nebo přeskočí testy na základě architektury procesu. Pomocí výčtu TestArchitectures příznaků určete, které architektury se vztahují.

[TestClass]
public class ArchitectureTests
{
    [TestMethod]
    [ArchitectureCondition(TestArchitectures.X64)]
    public void RunsOnX64()
    {
    }

    [TestMethod]
    [ArchitectureCondition(ConditionMode.Exclude, TestArchitectures.X86)]
    public void SkippedOnX86()
    {
    }
}

ExecutableConditionAttribute

, ExecutableConditionAttributepředstavený v MSTest 4.3, spouští nebo přeskočí testy na základě toho, zda je k dispozici externí nástroj. Test se spustí pouze tehdy, pokud lze zadaný spustitelný soubor nalézt; volitelně můžete předat argumenty, které se použijí při ověřování nástroje.

[TestClass]
public class ToolTests
{
    [TestMethod]
    [ExecutableCondition("git")]
    public void RunsWhenGitIsAvailable()
    {
    }

    [TestMethod]
    [ExecutableCondition("docker", "--version")]
    public void RunsWhenDockerResponds()
    {
    }
}

IgnoreAttribute

IgnoreAttribute přeskočí bezpodmínečně testovací třídu nebo metodu. Volitelně můžete zadat důvod ignorování.

Návod

Související analyzátor: MSTEST0015 – Testovací metoda by neměla být ignorována. Povolte tento analyzátor, aby zjistil testy, které jsou trvale ignorovány.

[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
}

Při ignorování testů kvůli známým problémům použijte WorkItemAttribute nebo GitHubWorkItemAttribute pro sledovatelnost:

[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
    }
}

Osvědčené postupy

  1. Používejte paralelizaci moudře: Povolte paralelizaci pro nezávislé testy, ale použijte DoNotParallelize je pro testy, které sdílejí stav.

  2. Nastavte vhodné časové limity: Zvolte časové limity, které umožňují normální spuštění, ale zachytí zablokované testy. Zvažte pomalé prostředí CI.

  3. Preferujte kooperativní zrušení: Používejte kooperativní zrušení, abyste se vyhnuli režii navíc spojené s dodatečnými obalovacími mechanismy úkolů a zabránili provádění časově omezených testů na pozadí. Pokud chcete tento postup vynutit, povolte analyzátor MSTEST0045 .

  4. Ignorované testy dokumentu: Při ignorování testů vždy uveďte důvod a odkaz na pracovní položku.

  5. Opakování používejte střídmě: Vyřešte původní příčinu nestabilních testů a nespoléhat na opakování.

  6. Vhodným způsobem otestujte kód specifický pro operační systém: Slouží OSCondition ke spouštění testů specifických pro platformu jenom tam, kde je to možné.

Viz také