Dela via


Testkörning och kontroll i MSTest

MSTest tillhandahåller attribut för att styra hur tester körs, inklusive parallellisering, trådningsmodeller, tidsgränser, återförsök och villkorsstyrd körning baserat på plattform eller miljö.

Trådningsegenskaper

Trådattribut styr vilka testmetoder för trådmodeller som används. Dessa attribut är viktiga när du testar COM-komponenter, gränssnittselement eller kod med specifika trådkrav.

STATestClassAttribute

Kör STATestClassAttribute alla testmetoder i en klass (inklusive ClassInitialize och ClassCleanup) i en enkeltrådad lägenhet (STA). Använd det här attributet när du testar COM-objekt som kräver STA.

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

Anmärkning

Det här attributet stöds endast i Windows i MSTest v3.6 och senare.

STATestMethodAttribute

Kör STATestMethodAttribute en specifik testmetod i en entrådad lägenhet. Använd det här attributet för enskilda tester som behöver STA medan andra tester i klassen inte gör det.

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

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

Anmärkning

Det här attributet stöds endast i Windows i MSTest v3.6 och senare.

Bevara STA-kontext för asynkrona fortsättningar

Från och med MSTest 4.1 inkluderar STATestMethodAttribute en egenskap UseSTASynchronizationContext som säkerställer att asynkrona fortsättningar körs på samma STA-tråd. När det är aktiverat skapar attributet en anpassad SynchronizationContext som publicerar fortsättningar tillbaka till STA-tråden, vilket är viktigt för testning av gränssnittskomponenter som kräver STA-trådning under hela asynkrona åtgärder.

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

Tips/Råd

Använd UseSTASynchronizationContext = true när du testar Windows Forms- eller WPF-komponenter som utför asynkrona åtgärder och förväntar sig att deras fortsättningar ska köras på samma tråd.

UITestMethodAttribute

Attributet UITestMethod schemalägger testkörning i användargränssnittstråden. Det här attributet är utformat för att testa UWP- och WinUI-program som kräver UI-trådåtkomst.

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

Anmärkning

Det här attributet kräver lämplig MSTest-adapter för UWP- eller WinUI-plattformar. Mer information finns i avsnittet plattformsstöd .

Parallelliseringsattribut

Parallelliseringsattribut styr om och hur tester körs samtidigt, vilket förbättrar testkörningstiden.

ParallelizeAttribute

Som standard kör MSTest tester sekventiellt. Attributet ParallelizeAttribute på sammansättningsnivå möjliggör parallell testkörning.

using Microsoft.VisualStudio.TestTools.UnitTesting;

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

Parallelliseringsomfång

Omfång Beteende
ClassLevel Flera testklasser körs parallellt, men tester i en klass körs sekventiellt
MethodLevel Enskilda testmetoder kan köras parallellt, oavsett klass

Arbetartrådar

Egenskapen Workers anger det maximala antalet trådar för parallell körning:

  • 0 (standard): Använd antalet logiska processorer på datorn
  • Valfritt positivt heltal: Använd det angivna antalet trådar
// Parallelize at class level with 2 worker threads
[assembly: Parallelize(Workers = 2, Scope = ExecutionScope.ClassLevel)]

Tips/Råd

Du kan också konfigurera parallellisering via körinställningar eller testconfig.json utan att ändra kod.

Tips/Råd

Aktivera parallellisering på sammansättningsnivå som standard, även om många tester för närvarande kräver sekventiell körning. Den här metoden uppmuntrar till att skriva nya tester som stöder parallell körning från början. Använd MSTEST0001 analyzer för att säkerställa att varje testklass uttryckligen deklarerar sin parallelliserings avsikt, vilket tvingar dig att granska om varje klass på ett säkert sätt stöder samtidig körning. Ofta räcker det att bara utesluta några klasser eller metoder med DoNotParallelize , vilket gör att majoriteten av dina tester kan köras parallellt för betydligt snabbare testkörning.

DoNotParallelizeAttribute

DoNotParallelizeAttribute Förhindrar parallell körning för specifika sammansättningar, klasser eller metoder. Använd det här attributet när tester delar tillstånd eller resurser som inte kan nås på ett säkert sätt samtidigt.

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

Anmärkning

Du behöver DoNotParallelize bara när du har aktiverat parallell körning med attributet Parallelize .

Timeout-attribut

Timeout-attribut hindrar tester från att köras på obestämd tid och hjälper till att identifiera prestandaproblem.

TimeoutAttribute

TimeoutAttribute Anger den maximala tid (i millisekunder) som en test- eller fixturmetod kan köra. Om körningen överskrider den här tiden misslyckas testet.

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

Tips/Råd

Du kan konfigurera en global tidsgräns för test via runsettings (TestTimeout) eller testconfig.json (timeout.test) utan att ändra kod.

Tillämpa timeout på fixeringsmetoder

Du kan också använda tidsgränser för initierings- och rensningsmetoder.

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

Tips/Råd

Varje fixturmetod som accepterar ett [Timeout] attribut har en motsvarande global konfigurationsinställning. Konfigurera tidsgränser globalt via runsettings eller testconfig.json med hjälp av inställningar som TestInitializeTimeout, ClassInitializeTimeout, AssemblyInitializeTimeout och deras motsvarigheter för borttagning.

Anmärkning

Tidsgränser är inte garanterade att vara exakt korrekta. Testet avbryts när den angivna tiden har passerat, men den faktiska annulleringen kan ta lite längre tid.

Kooperativ avbokning

Som standard omsluter MSTest varje tidsinställda testmetod i en separat uppgift eller tråd. När tidsgränsen nås slutar ramverket att observera testet, men den underliggande aktiviteten fortsätter att köras i bakgrunden. Det här beteendet kan orsaka problem:

  • Testmetoden fortsätter att komma åt resurser och mutera tillstånd även efter timeout.
  • Bakgrundskörning kan leda till konkurrensförhållanden som påverkar efterföljande tester.
  • Varje tidsstyrd metod medför ytterligare belastning från uppgifts-/trådinkapslingen.

Från och med MSTest 3.6 använder du CooperativeCancellation egenskapen för att undvika dessa problem. I samarbetsläge omsluter MSTest inte testet i en extra uppgift. När tidsgränsen nås signalerar ramverket i stället annulleringstoken. Din testkod ansvarar för att kontrollera token regelbundet och avsluta på ett smidigt sätt.

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

Fördelar med kooperativ annullering:

  • Lägre prestandaomkostnader (ingen extra uppgift/trådomslutning per test).
  • Renare resursrensning eftersom koden uttryckligen hanterar annullering.
  • Överensstämmer med standardmönster för .NET-annullering.
  • Deterministiskt beteende genom att undvika konkurrensförhållanden mellan testkod och obemärkt bakgrundskörning.

Anmärkning

Kooperativ annullering kräver att din testkod regelbundet kontrollerar annulleringstoken. Om koden inte kontrollerar token stoppas inte testet när tidsgränsen nås.

Tips/Råd

Du kan aktivera kooperativ annullering globalt för alla timeout-attribut genom runsettings eller testconfig.json istället för att ställa in det för varje attribut individuellt.

Tips/Råd

Relaterade analysverktyg:

  • MSTEST0045 – rekommenderar att du använder kooperativ annullering för timeout-attribut.

Försök med attribut igen

Omförsöksattribut hjälper till att hantera flagnande tester genom att automatiskt köra misslyckade tester igen.

RetryAttribute

Den RetryAttribute, som introducerades i MSTest 3.8, återförsöker automatiskt testmetoder som misslyckas eller går ut på tid. Konfigurera maximalt antal försök, fördröjning mellan försök och backoff-strategi.

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

Konfigurationsalternativ

Fastighet Description Förinställning
MaxRetryAttempts Maximalt antal återförsök (skrivskyddat, inställt via konstruktor) Krävs
MillisecondsDelayBetweenRetries Basfördröjning mellan återförsök (i ms) 0
BackoffType Constant eller Exponential fördröjning Constant

Anmärkning

Endast en RetryAttribute får finnas i en testmetod. Du kan inte använda RetryAttribute på metoder som inte är markerade med TestMethod.

Tips/Råd

Relaterade analysverktyg:

  • MSTEST0043 – rekommenderar att du använder RetryAttribute på testmetoder.

Anpassade återförsöksimplementeringar

Skapa anpassad logik för återförsök genom att ärva från RetryBaseAttribute:

public class CustomRetryAttribute : RetryBaseAttribute
{
    private readonly int _maxRetries;

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

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

Attribut för villkorsstyrd körning

Attribut för villkorsstyrd körning styr om tester körs baserat på specifika villkor som operativsystem eller CI-miljö.

ConditionBaseAttribute

ConditionBaseAttribute är den abstrakta basklassen för villkorsstyrd körning. MSTest innehåller flera inbyggda implementeringar.

Anmärkning

Som standard ärvs inte villkorsattribut. Att tillämpa dem på en basklass påverkar inte härledda klasser. Anpassade villkorsattribut kan åsidosätta det här beteendet genom att omdefiniera AttributeUsage, men detta rekommenderas inte för att upprätthålla konsekvens med de inbyggda villkorsattributen.

Tips/Råd

Relaterade analysverktyg:

  • MSTEST0041 – rekommenderar att du använder villkorsbaserade attribut med testklasser.

OSConditionAttribute

Beroende på operativsystemet kör eller hoppar OSConditionAttribute över tester. Använd flaggorna OperatingSystems för att ange vilka operativsystem som ska tillämpas.

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

Operativsystem som stöds

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

Kombinera operativsystem med bitvis ELLER-operatorn (|).

Tips/Råd

Relaterade analysverktyg:

  • MSTEST0061 – rekommenderar att du använder OSCondition attribut istället för körningstidskontroller.

CIConditionAttribute

Kör CIConditionAttribute eller hoppar över tester baserat på om de körs i en kontinuerlig integrationsmiljö.

[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

Utan förbehåll hoppar IgnoreAttribute över en testklass eller metod. Du kan också ange en orsak till att ignorera.

Tips/Råd

Relaterat analysverktyg: MSTEST0015 – Testmetoden bör inte ignoreras. Aktivera den här analyseraren för att identifiera tester som ignoreras permanent.

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

När du ignorerar tester på grund av kända problem kan du använda WorkItemAttribute eller GitHubWorkItemAttribute för spårbarhet.

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

Metodtips

  1. Använd parallellisering klokt: Aktivera parallellisering för oberoende tester, men använd DoNotParallelize för tester som delar tillstånd.

  2. Ange lämpliga tidsgränser: Välj tidsgränser som tillåter normal körning men fångar upp fastnade tester. Överväg långsamma CI-miljöer.

  3. Föredrar kooperativ annullering: Använd kooperativ annullering för att undvika extra aktivitetsomslutningar och förhindra bakgrundskörning av tidsgränstester. Aktivera MSTEST0045-analysatorn för att tillämpa den här metoden.

  4. Dokumentera ignorerade tester: Ange alltid en orsak och en referens till arbetsobjekt när du ignorerar tester.

  5. Använd återförsök sparsamt: Åtgärda rotorsaken till flagnande tester i stället för att förlita sig på återförsök.

  6. Testa OS-specifik kod på lämpligt sätt: Använd OSCondition för att köra plattformsspecifika tester endast där de är tillämpliga.

Se även