From 728aaaf04feeb2cb87a0808d4431a8f24f23125d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Thu, 28 May 2026 10:43:55 +0200 Subject: [PATCH 1/4] Add MSTEST0066 analyzer to flag Thread.Sleep/Task.Wait/Task.Result in tests Fixes #6950. Adds a new MSTEST0066 'AvoidThreadSleepAndTaskWaitInTests' analyzer that reports an Info-level diagnostic when one of the following blocking APIs is invoked inside a test method or fixture method (TestInitialize/TestCleanup/ClassInitialize/ClassCleanup/AssemblyInitialize/AssemblyCleanup/GlobalTestInitialize/GlobalTestCleanup): - Thread.Sleep(...) - Task.Wait(...) (including Task.Wait) - Task.Result The walk also looks through local functions and lambda bodies declared inside such methods so a Thread.Sleep buried in a callback still surfaces. The issue text mentioned 'Thread.Wait' which does not exist on System.Threading.Thread; this is interpreted as Task.Wait, which is the actual flakiness/deadlock source. Scope was extended to Task.Result for the same reason. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AnalyzerReleases.Unshipped.md | 1 + ...idThreadSleepAndTaskWaitInTestsAnalyzer.cs | 204 ++++++++ .../MSTest.Analyzers/Helpers/DiagnosticIds.cs | 1 + .../Helpers/WellKnownTypeNames.cs | 1 + src/Analyzers/MSTest.Analyzers/Resources.resx | 9 + .../MSTest.Analyzers/xlf/Resources.cs.xlf | 15 + .../MSTest.Analyzers/xlf/Resources.de.xlf | 15 + .../MSTest.Analyzers/xlf/Resources.es.xlf | 15 + .../MSTest.Analyzers/xlf/Resources.fr.xlf | 15 + .../MSTest.Analyzers/xlf/Resources.it.xlf | 15 + .../MSTest.Analyzers/xlf/Resources.ja.xlf | 15 + .../MSTest.Analyzers/xlf/Resources.ko.xlf | 15 + .../MSTest.Analyzers/xlf/Resources.pl.xlf | 15 + .../MSTest.Analyzers/xlf/Resources.pt-BR.xlf | 15 + .../MSTest.Analyzers/xlf/Resources.ru.xlf | 15 + .../MSTest.Analyzers/xlf/Resources.tr.xlf | 15 + .../xlf/Resources.zh-Hans.xlf | 15 + .../xlf/Resources.zh-Hant.xlf | 15 + ...eadSleepAndTaskWaitInTestsAnalyzerTests.cs | 442 ++++++++++++++++++ 19 files changed, 853 insertions(+) create mode 100644 src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs create mode 100644 test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs diff --git a/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md b/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md index 3421a0b608..9ad427be20 100644 --- a/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md +++ b/src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md @@ -7,3 +7,4 @@ Rule ID | Category | Severity | Notes --------|----------|----------|------- MSTEST0064 | Usage | Info | PreferAsyncAssertionAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0064) MSTEST0065 | Usage | Warning | AvoidAssertAreEqualOnCollectionsAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0065) +MSTEST0066 | Usage | Info | AvoidThreadSleepAndTaskWaitInTestsAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0066) diff --git a/src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs new file mode 100644 index 0000000000..5e850fa039 --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; + +using Analyzer.Utilities.Extensions; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; + +using MSTest.Analyzers.Helpers; + +namespace MSTest.Analyzers; + +/// +/// MSTEST0064: . +/// +[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] +public sealed class AvoidThreadSleepAndTaskWaitInTestsAnalyzer : DiagnosticAnalyzer +{ + private static readonly LocalizableResourceString Title = new(nameof(Resources.AvoidThreadSleepAndTaskWaitInTestsTitle), Resources.ResourceManager, typeof(Resources)); + private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.AvoidThreadSleepAndTaskWaitInTestsMessageFormat), Resources.ResourceManager, typeof(Resources)); + private static readonly LocalizableResourceString Description = new(nameof(Resources.AvoidThreadSleepAndTaskWaitInTestsDescription), Resources.ResourceManager, typeof(Resources)); + + internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create( + DiagnosticIds.AvoidThreadSleepAndTaskWaitInTestsRuleId, + Title, + MessageFormat, + Description, + Category.Usage, + DiagnosticSeverity.Info, + isEnabledByDefault: true); + + /// + public override ImmutableArray SupportedDiagnostics { get; } + = ImmutableArray.Create(Rule); + + /// + public override void Initialize(AnalysisContext context) + { + context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + + context.RegisterCompilationStartAction(context => + { + Compilation compilation = context.Compilation; + INamedTypeSymbol? threadSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingThread); + INamedTypeSymbol? taskSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask); + INamedTypeSymbol? taskOfTSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask1); + + // Collect the set of attribute symbols that mark a method as "test code". + ImmutableHashSet testRelatedAttributeSymbols = GetTestRelatedAttributeSymbols(compilation); + INamedTypeSymbol? testMethodAttributeSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestMethodAttribute); + + // If no test attribute is available in this compilation, there is nothing to analyze. + if (testRelatedAttributeSymbols.IsEmpty && testMethodAttributeSymbol is null) + { + return; + } + + if (threadSymbol is not null || taskSymbol is not null || taskOfTSymbol is not null) + { + context.RegisterOperationAction( + context => AnalyzeInvocation(context, threadSymbol, taskSymbol, taskOfTSymbol, testRelatedAttributeSymbols, testMethodAttributeSymbol), + OperationKind.Invocation); + } + + if (taskOfTSymbol is not null) + { + context.RegisterOperationAction( + context => AnalyzePropertyReference(context, taskOfTSymbol, testRelatedAttributeSymbols, testMethodAttributeSymbol), + OperationKind.PropertyReference); + } + }); + } + + private static void AnalyzeInvocation( + OperationAnalysisContext context, + INamedTypeSymbol? threadSymbol, + INamedTypeSymbol? taskSymbol, + INamedTypeSymbol? taskOfTSymbol, + ImmutableHashSet testRelatedAttributeSymbols, + INamedTypeSymbol? testMethodAttributeSymbol) + { + var invocation = (IInvocationOperation)context.Operation; + IMethodSymbol targetMethod = invocation.TargetMethod; + + string? offendingApi = null; + if (threadSymbol is not null + && targetMethod is { Name: "Sleep", IsStatic: true } + && SymbolEqualityComparer.Default.Equals(targetMethod.ContainingType, threadSymbol)) + { + offendingApi = "Thread.Sleep"; + } + else if (targetMethod is { Name: "Wait", IsStatic: false } + && (SymbolEqualityComparer.Default.Equals(targetMethod.ContainingType, taskSymbol) + || (taskOfTSymbol is not null && IsConstructedFrom(targetMethod.ContainingType, taskOfTSymbol)))) + { + offendingApi = "Task.Wait"; + } + + if (offendingApi is null) + { + return; + } + + if (!IsInsideTestCode(context.ContainingSymbol, testRelatedAttributeSymbols, testMethodAttributeSymbol)) + { + return; + } + + context.ReportDiagnostic(invocation.CreateDiagnostic(Rule, offendingApi)); + } + + private static void AnalyzePropertyReference( + OperationAnalysisContext context, + INamedTypeSymbol taskOfTSymbol, + ImmutableHashSet testRelatedAttributeSymbols, + INamedTypeSymbol? testMethodAttributeSymbol) + { + var propertyReference = (IPropertyReferenceOperation)context.Operation; + IPropertySymbol property = propertyReference.Property; + + if (property is not { Name: "Result", IsStatic: false } + || !IsConstructedFrom(property.ContainingType, taskOfTSymbol)) + { + return; + } + + if (!IsInsideTestCode(context.ContainingSymbol, testRelatedAttributeSymbols, testMethodAttributeSymbol)) + { + return; + } + + context.ReportDiagnostic(propertyReference.CreateDiagnostic(Rule, "Task.Result")); + } + + private static bool IsConstructedFrom(INamedTypeSymbol? typeSymbol, INamedTypeSymbol genericDefinition) + => typeSymbol is not null && SymbolEqualityComparer.Default.Equals(typeSymbol.OriginalDefinition, genericDefinition); + + private static bool IsInsideTestCode( + ISymbol? containingSymbol, + ImmutableHashSet testRelatedAttributeSymbols, + INamedTypeSymbol? testMethodAttributeSymbol) + { + // Walk up through local functions / lambdas to find the enclosing user-declared method. + ISymbol? current = containingSymbol; + while (current is IMethodSymbol method) + { + foreach (AttributeData attribute in method.GetAttributes()) + { + INamedTypeSymbol? attributeClass = attribute.AttributeClass; + if (attributeClass is null) + { + continue; + } + + if (testRelatedAttributeSymbols.Contains(attributeClass)) + { + return true; + } + + if (testMethodAttributeSymbol is not null && attributeClass.Inherits(testMethodAttributeSymbol)) + { + return true; + } + } + + // Continue walking only when the symbol is synthesized from a local function / lambda body. + if (method.MethodKind is MethodKind.LocalFunction or MethodKind.AnonymousFunction) + { + current = method.ContainingSymbol; + continue; + } + + return false; + } + + return false; + } + + private static ImmutableHashSet GetTestRelatedAttributeSymbols(Compilation compilation) + { + ImmutableHashSet.Builder builder = ImmutableHashSet.CreateBuilder(SymbolEqualityComparer.Default); + AddIfPresent(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestInitializeAttribute); + AddIfPresent(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestCleanupAttribute); + AddIfPresent(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassInitializeAttribute); + AddIfPresent(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingClassCleanupAttribute); + AddIfPresent(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssemblyInitializeAttribute); + AddIfPresent(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingAssemblyCleanupAttribute); + AddIfPresent(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingGlobalTestInitializeAttribute); + AddIfPresent(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingGlobalTestCleanupAttribute); + return builder.ToImmutable(); + + void AddIfPresent(string metadataName) + { + if (compilation.GetOrCreateTypeByMetadataName(metadataName) is { } symbol) + { + builder.Add(symbol); + } + } + } +} diff --git a/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs b/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs index d98d81ac05..5e06df6ebb 100644 --- a/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs +++ b/src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs @@ -70,4 +70,5 @@ internal static class DiagnosticIds public const string TestClassConstructorShouldBeValidRuleId = "MSTEST0063"; public const string PreferAsyncAssertionRuleId = "MSTEST0064"; public const string AvoidAssertAreEqualOnCollectionsRuleId = "MSTEST0065"; + public const string AvoidThreadSleepAndTaskWaitInTestsRuleId = "MSTEST0066"; } diff --git a/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs b/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs index fbd3c14623..69a0d144e2 100644 --- a/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs +++ b/src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs @@ -63,4 +63,5 @@ internal static class WellKnownTypeNames public const string SystemThreadingTasksTask1 = "System.Threading.Tasks.Task`1"; public const string SystemThreadingTasksValueTask = "System.Threading.Tasks.ValueTask"; public const string SystemThreadingTasksValueTask1 = "System.Threading.Tasks.ValueTask`1"; + public const string SystemThreadingThread = "System.Threading.Thread"; } diff --git a/src/Analyzers/MSTest.Analyzers/Resources.resx b/src/Analyzers/MSTest.Analyzers/Resources.resx index a343119cf7..423c82facb 100644 --- a/src/Analyzers/MSTest.Analyzers/Resources.resx +++ b/src/Analyzers/MSTest.Analyzers/Resources.resx @@ -756,6 +756,15 @@ The type declaring these methods should also respect the following rules: Test classes must have a public constructor that is either parameterless or accepts a single TestContext parameter. This allows the test framework to instantiate the test class properly. + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Prefer async assertion methods diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf index 7b479b51cc..e0559df54f 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf @@ -157,6 +157,21 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: Vyhněte se předávání explicitního typu DynamicDataSourceType a použijte výchozí chování automatického zjišťování. + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. Nepoužívejte výraz uvnitř metod async void, místních funkcí nebo výrazů lambda. Výjimky vyvolané v tomto kontextu budou neošetřené výjimky. Když používáte VSTest v .NET Framework, budou se bezobslužně používat. Když používáte Microsoft.Testing.Platform nebo VSTest v moderním rozhraní .NET, může dojít k chybovému ukončení procesu. diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf index c41d6d7568..d27cd6c025 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf @@ -157,6 +157,21 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte Vermeiden Sie die explizite Übergabe von „DynamicDataSourceType” und verwenden Sie das standardmäßige automatische Erkennungsverhalten. + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. Nicht innerhalb von "async void"-Methoden, lokalen Funktionen oder Lambdafunktionen bestätigen. Ausnahmen, die in diesem Kontext ausgelöst werden, werden nicht behandelt. Bei Verwendung von VSTest unter .NET Framework werden diese im Hintergrund verschlungen. Wenn Sie Microsoft.Testing.Platform oder VSTest unter modernem .NET verwenden, kann der Prozess abgestürzt werden. diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf index eb969d8508..5d7837b4d0 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf @@ -157,6 +157,21 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: Evite pasar un 'DynamicDataSourceType' explícito y utilice el comportamiento de detección automática predeterminado + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. No realice ninguna aserción dentro de métodos 'async void', funciones locales o expresiones lambda. Las excepciones que se inicien en este contexto serán excepciones no controladas. Al usar VSTest en .NET Framework, se ingerirán silenciosamente. Cuando se usa Microsoft.Testing.Platform o VSTest en .NET moderno, es posible que se bloquee el proceso. diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf index 9160442f0b..0773b6c67d 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf @@ -157,6 +157,21 @@ Le type doit être une classe Évitez de passer un type « DynamicDataSourceType » explicite et utilisez le comportement de détection automatique par défaut + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. N’effectuez pas d’assertion dans les méthodes 'async void', les fonctions locales ou les expressions lambda. Les exceptions levées dans ce contexte seront des exceptions non gérées. Lors de l’utilisation de VSTest sous .NET Framework, ils sont silencieusement coupés. Quand vous utilisez Microsoft.Testing.Platform ou VSTest sous .NET moderne, ils peuvent bloquer le processus. diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf index 593925ce2c..2a6f5e36d5 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf @@ -157,6 +157,21 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: Evitare di passare l'argomento 'DynamicDataSourceType' in modo esplicito e utilizzare il comportamento di rilevamento automatico predefinito + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. Non dichiarare all'interno di metodi 'async void', funzioni locali o espressioni lambda. Le eccezioni generate in questo contesto saranno eccezioni non gestite. Quando si usa VSTest in .NET Framework, verranno eliminati automaticamente. Quando si usa Microsoft.Testing.Platform o VSTest nella versione moderna di .NET, è possibile che il processo venga arrestato in modo anomalo. diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf index e40548e9ac..9ffdd7c72a 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf @@ -157,6 +157,21 @@ The type declaring these methods should also respect the following rules: 明示的な 'DynamicDataSourceType' を渡さず、既定の自動検出動作を使用してください + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. 'async void' メソッド、ローカル関数、またはラムダ内ではアサートしないでください。このコンテキストでスローされる例外は、ハンドルされない例外になります。.NET Frameworkで VSTest を使用すると、警告なしに飲み込まれるようになります。最新の .NET で Microsoft.Testing.Platform または VSTest を使用すると、プロセスがクラッシュする可能性があります。 diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf index 06978e1d7e..4d1839fd26 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf @@ -157,6 +157,21 @@ The type declaring these methods should also respect the following rules: 명시적 'DynamicDataSourceType'을 전달하지 말고 기본 자동 검색 동작을 사용합니다. + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. 'async void' 메서드, 로컬 함수 또는 람다 내에서 어설션하지 마십시오. 이 컨텍스트에서 throw된 예외는 처리되지 않은 예외가 됩니다. .NET Framework 아래에서 VSTest를 사용하면 자동으로 무시됩니다. 최신 .NET에서 Microsoft.Testing.Platform 또는 VSTest를 사용하는 경우 프로세스가 중단될 수 있습니다. diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf index e6a72d8857..eaba3d401b 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf @@ -157,6 +157,21 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu Unikaj przekazywania jawnego elementu „DynamicDataSourceType” i użyj domyślnego zachowania wykrywania automatycznego + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. Nie potwierdzaj wewnątrz metod "async void", funkcji lokalnych ani lambda. Wyjątki, które są zgłaszane w tym kontekście, będą nieobsługiwanymi wyjątkami. W przypadku korzystania z narzędzia VSTest w .NET Framework będą one dyskretnie ściszone. W przypadku korzystania z elementu Microsoft.Testing.Platform lub VSTest w nowoczesnych programach .NET mogą one spowodować awarię procesu. diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf index 009bd1593d..a2f061e549 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf @@ -157,6 +157,21 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: Evitar passar um "DynamicDataSourceType" explícito e usar o comportamento de detecção automática padrão + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. Não asserção dentro de métodos 'async void', funções locais ou lambdas. Exceções lançadas neste contexto serão exceções sem tratamento. Ao usar VSTest sob .NET Framework, eles serão silenciosamente ignoradas. Ao usar Microsoft.Testing.Platform ou VSTest em .NET moderno, o processo pode falhar. diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf index 2d32a5db2d..d58e190439 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf @@ -160,6 +160,21 @@ The type declaring these methods should also respect the following rules: Избегайте передачи явного DynamicDataSourceType и используйте поведение автоматического обнаружения по умолчанию + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. Не подтверяйте внутри методов async void, локальных функций или лямбда-выражений. Исключения, вызванные в этом контексте, будут необработанные исключения. При использовании VSTest платформа .NET Framework, они будут пропущены без уведомления. При использовании Microsoft.Testing.Platform или VSTest в современной версии .NET они могут привести к сбою процесса. diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf index 7dbc6913a6..eb541deb09 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf @@ -157,6 +157,21 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: Açık bir ‘DynamicDataSourceType’ geçirmeyin ve varsayılan otomatik algılama davranışını kullanın + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. 'async void' metotları, yerel işlevler veya lambdalar içinde onaylamayın. Bu bağlamda oluşturulan özel durumlar işlenmeyen özel durumlar olacak. VsTest'i .NET Framework, sessizce kırılır. Modern .NET altında Microsoft.Testing.Platform veya VSTest kullanırken işlemi kilitler. diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf index 5e364f9b6f..cc9b5c1b6f 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf @@ -157,6 +157,21 @@ The type declaring these methods should also respect the following rules: 避免传递显式 "DynamicDataSourceType" 并使用默认的自动检测行为 + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. 不要在 “async void” 方法、本地函数或 lambdas 内断言。在此上下文中引发的异常将是未经处理的异常。在.NET Framework下使用 VSTest 时,将无提示地接受这些测试。在现代 .NET 下使用 Microsoft.Testing.Platform 或 VSTest 时,它们可能会导致进程崩溃。 diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf index 1b63af18ad..4696359903 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf @@ -157,6 +157,21 @@ The type declaring these methods should also respect the following rules: 避免傳遞明確的 'DynamicDataSourceType',並使用預設的自動偵測行為 + + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + + + + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task + + + + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid 'Thread.Sleep' and 'Task.Wait' in test code + + Do not assert inside 'async void' methods, local functions, or lambdas. Exceptions that are thrown in this context will be unhandled exceptions. When using VSTest under .NET Framework, they will be silently swallowed. When using Microsoft.Testing.Platform or VSTest under modern .NET, they may crash the process. 不要在 'async void' 方法、本機函數或 lambdas 內判斷提示。在此內容中擲回的例外狀況將會是未處理的例外狀況。在 .NET Framework 下使用 VSTest 時,會以無訊息方式接受。在現代 .NET 下使用 Microsoft.Testing.Platform 或 VSTest 時,可能會損毀進程。 diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs new file mode 100644 index 0000000000..548700599c --- /dev/null +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs @@ -0,0 +1,442 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using VerifyCS = MSTest.Analyzers.Test.CSharpCodeFixVerifier< + MSTest.Analyzers.AvoidThreadSleepAndTaskWaitInTestsAnalyzer, + Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; + +namespace MSTest.Analyzers.UnitTests; + +[TestClass] +public sealed class AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests +{ + [TestMethod] + public async Task ThreadSleepInTestMethod_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + [|Thread.Sleep(100)|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepWithTimeSpanInTestMethod_Diagnostic() + { + string code = """ + using System; + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + [|Thread.Sleep(TimeSpan.FromSeconds(1))|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInDataTestMethod_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [DataTestMethod] + [DataRow(1)] + public void TestMethod(int value) + { + [|Thread.Sleep(100)|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInTestInitialize_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestInitialize] + public void Setup() + { + [|Thread.Sleep(100)|]; + } + + [TestMethod] + public void TestMethod() { } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInTestCleanup_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestCleanup] + public void Cleanup() + { + [|Thread.Sleep(100)|]; + } + + [TestMethod] + public void TestMethod() { } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInClassInitialize_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [ClassInitialize] + public static void ClassInit(TestContext context) + { + [|Thread.Sleep(100)|]; + } + + [TestMethod] + public void TestMethod() { } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInAssemblyInitialize_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [AssemblyInitialize] + public static void AssemblyInit(TestContext context) + { + [|Thread.Sleep(100)|]; + } + + [TestMethod] + public void TestMethod() { } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInHelperMethodInTestClass_NoDiagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + private void Helper() + { + Thread.Sleep(100); + } + + [TestMethod] + public void TestMethod() { } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInNonTestClass_NoDiagnostic() + { + string code = """ + using System.Threading; + + public class MyClass + { + public void DoSomething() + { + Thread.Sleep(100); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInLocalFunctionInsideTestMethod_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + void Local() + { + [|Thread.Sleep(100)|]; + } + + Local(); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInLambdaInsideTestMethod_Diagnostic() + { + string code = """ + using System; + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + Action action = () => [|Thread.Sleep(100)|]; + action(); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task TaskWaitInTestMethod_Diagnostic() + { + string code = """ + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + Task task = Task.CompletedTask; + [|task.Wait()|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task TaskWaitWithTimeoutInTestMethod_Diagnostic() + { + string code = """ + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + Task task = Task.CompletedTask; + [|task.Wait(1000)|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task TaskOfTWaitInTestMethod_Diagnostic() + { + string code = """ + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + Task task = Task.FromResult(42); + [|task.Wait()|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task TaskOfTResultInTestMethod_Diagnostic() + { + string code = """ + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + Task task = Task.FromResult(42); + int value = [|task.Result|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task AwaitTaskInTestMethod_NoDiagnostic() + { + string code = """ + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public async Task TestMethod() + { + await Task.Delay(100); + int value = await Task.FromResult(42); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task TaskWaitInHelperMethodInTestClass_NoDiagnostic() + { + string code = """ + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + private void Helper() + { + Task task = Task.CompletedTask; + task.Wait(); + } + + [TestMethod] + public void TestMethod() { } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task TaskFactoryStartNewWaitInTestMethod_Diagnostic() + { + string code = """ + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + [|Task.Run(() => { }).Wait()|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task SemaphoreWaitInTestMethod_NoDiagnostic() + { + // SemaphoreSlim.Wait is intentionally not in scope; it is a synchronization primitive, + // not a sync-over-async pattern, so we should not report it. + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + var sem = new SemaphoreSlim(1); + sem.Wait(); + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } +} From e712ed48accc3c50b5add16bf03fbbe06c11803e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Thu, 28 May 2026 11:52:29 +0200 Subject: [PATCH 2/4] Address review feedback - Fix XML doc rule ID (MSTEST0064 -> MSTEST0066) on the analyzer summary. - Expand rule title to also mention Task.Result, matching the analyzer's reported scope. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs | 2 +- src/Analyzers/MSTest.Analyzers/Resources.resx | 2 +- src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf | 4 ++-- src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf | 4 ++-- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs index 5e850fa039..4662b59a54 100644 --- a/src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs @@ -14,7 +14,7 @@ namespace MSTest.Analyzers; /// -/// MSTEST0064: . +/// MSTEST0066: . /// [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] public sealed class AvoidThreadSleepAndTaskWaitInTestsAnalyzer : DiagnosticAnalyzer diff --git a/src/Analyzers/MSTest.Analyzers/Resources.resx b/src/Analyzers/MSTest.Analyzers/Resources.resx index 423c82facb..24f2d90a40 100644 --- a/src/Analyzers/MSTest.Analyzers/Resources.resx +++ b/src/Analyzers/MSTest.Analyzers/Resources.resx @@ -757,7 +757,7 @@ The type declaring these methods should also respect the following rules: Test classes must have a public constructor that is either parameterless or accepts a single TestContext parameter. This allows the test framework to instantiate the test class properly. - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf index e0559df54f..e9e467ad2c 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf @@ -168,8 +168,8 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf index d27cd6c025..6df11e57c4 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf @@ -168,8 +168,8 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf index 5d7837b4d0..264e677f7b 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf @@ -168,8 +168,8 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf index 0773b6c67d..61eaa1b3ab 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf @@ -168,8 +168,8 @@ Le type doit être une classe - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf index 2a6f5e36d5..cff6a3406b 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf @@ -168,8 +168,8 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf index 9ffdd7c72a..2a7a12a9d6 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf @@ -168,8 +168,8 @@ The type declaring these methods should also respect the following rules: - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf index 4d1839fd26..307ee3ce6c 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf @@ -168,8 +168,8 @@ The type declaring these methods should also respect the following rules: - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf index eaba3d401b..fdb30c36c8 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf @@ -168,8 +168,8 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf index a2f061e549..21aca247ea 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf @@ -168,8 +168,8 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf index d58e190439..12fbdc0d43 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf @@ -171,8 +171,8 @@ The type declaring these methods should also respect the following rules: - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf index eb541deb09..c69c4cac2d 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf @@ -168,8 +168,8 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf index cc9b5c1b6f..38c9522c86 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf @@ -168,8 +168,8 @@ The type declaring these methods should also respect the following rules: - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf index 4696359903..2409297611 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf @@ -168,8 +168,8 @@ The type declaring these methods should also respect the following rules: - Avoid 'Thread.Sleep' and 'Task.Wait' in test code - Avoid 'Thread.Sleep' and 'Task.Wait' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code From 38f35f486849224e39b4f89ddecece64a5516429 Mon Sep 17 00:00:00 2001 From: Evangelink <11340282+Evangelink@users.noreply.github.com> Date: Thu, 28 May 2026 14:27:30 +0200 Subject: [PATCH 3/4] Address review: add Task.WaitAll/WaitAny detection and expand test coverage - Detect static Task.WaitAll / Task.WaitAny as blocking calls. - Update title/description resources and regenerate xlf files. - Add tests for ClassCleanup, AssemblyCleanup, GlobalTestInitialize, GlobalTestCleanup. - Add test for custom attribute deriving from TestMethodAttribute. - Add expression-bodied test method case. - Add VB smoke tests (Thread.Sleep and Task(Of T).Result). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...idThreadSleepAndTaskWaitInTestsAnalyzer.cs | 6 + src/Analyzers/MSTest.Analyzers/Resources.resx | 4 +- .../MSTest.Analyzers/xlf/Resources.cs.xlf | 8 +- .../MSTest.Analyzers/xlf/Resources.de.xlf | 8 +- .../MSTest.Analyzers/xlf/Resources.es.xlf | 8 +- .../MSTest.Analyzers/xlf/Resources.fr.xlf | 8 +- .../MSTest.Analyzers/xlf/Resources.it.xlf | 8 +- .../MSTest.Analyzers/xlf/Resources.ja.xlf | 8 +- .../MSTest.Analyzers/xlf/Resources.ko.xlf | 8 +- .../MSTest.Analyzers/xlf/Resources.pl.xlf | 8 +- .../MSTest.Analyzers/xlf/Resources.pt-BR.xlf | 8 +- .../MSTest.Analyzers/xlf/Resources.ru.xlf | 8 +- .../MSTest.Analyzers/xlf/Resources.tr.xlf | 8 +- .../xlf/Resources.zh-Hans.xlf | 8 +- .../xlf/Resources.zh-Hant.xlf | 8 +- ...eadSleepAndTaskWaitInTestsAnalyzerTests.cs | 242 ++++++++++++++++++ 16 files changed, 302 insertions(+), 54 deletions(-) diff --git a/src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs index 4662b59a54..05aae5bee0 100644 --- a/src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/AvoidThreadSleepAndTaskWaitInTestsAnalyzer.cs @@ -99,6 +99,12 @@ private static void AnalyzeInvocation( { offendingApi = "Task.Wait"; } + else if (taskSymbol is not null + && targetMethod is { Name: "WaitAll" or "WaitAny", IsStatic: true } + && SymbolEqualityComparer.Default.Equals(targetMethod.ContainingType, taskSymbol)) + { + offendingApi = $"Task.{targetMethod.Name}"; + } if (offendingApi is null) { diff --git a/src/Analyzers/MSTest.Analyzers/Resources.resx b/src/Analyzers/MSTest.Analyzers/Resources.resx index 24f2d90a40..14d6809d7b 100644 --- a/src/Analyzers/MSTest.Analyzers/Resources.resx +++ b/src/Analyzers/MSTest.Analyzers/Resources.resx @@ -757,13 +757,13 @@ The type declaring these methods should also respect the following rules: Test classes must have a public constructor that is either parameterless or accepts a single TestContext parameter. This allows the test framework to instantiate the test class properly. - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code Avoid '{0}' in test code as it can cause test flakiness; consider an asynchronous alternative such as 'await Task.Delay' or 'await' the task - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. Prefer async assertion methods diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf index e9e467ad2c..d69d9f6f36 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf @@ -158,8 +158,8 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla: - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf index 6df11e57c4..4ec2f8d068 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf @@ -158,8 +158,8 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf index 264e677f7b..0110422c9e 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf @@ -158,8 +158,8 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes: - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf index 61eaa1b3ab..d8da509b29 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf @@ -158,8 +158,8 @@ Le type doit être une classe - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ Le type doit être une classe - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf index cff6a3406b..faf23cdfb1 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf @@ -158,8 +158,8 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ Anche il tipo che dichiara questi metodi deve rispettare le regole seguenti: - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf index 2a7a12a9d6..fabac8f49c 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ja.xlf @@ -158,8 +158,8 @@ The type declaring these methods should also respect the following rules: - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ The type declaring these methods should also respect the following rules: - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf index 307ee3ce6c..2d385d90c9 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ko.xlf @@ -158,8 +158,8 @@ The type declaring these methods should also respect the following rules: - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ The type declaring these methods should also respect the following rules: - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf index fdb30c36c8..7014ce68fc 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pl.xlf @@ -158,8 +158,8 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ Typ deklarujący te metody powinien również przestrzegać następujących regu - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf index 21aca247ea..72200e3e52 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.pt-BR.xlf @@ -158,8 +158,8 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ O tipo que declara esses métodos também deve respeitar as seguintes regras: - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf index 12fbdc0d43..f7bdce479f 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.ru.xlf @@ -161,8 +161,8 @@ The type declaring these methods should also respect the following rules: - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -171,8 +171,8 @@ The type declaring these methods should also respect the following rules: - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf index c69c4cac2d..87d71b083d 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.tr.xlf @@ -158,8 +158,8 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ Bu yöntemleri bildiren tipin ayrıca aşağıdaki kurallara uyması gerekir: - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf index 38c9522c86..4b48f6e064 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hans.xlf @@ -158,8 +158,8 @@ The type declaring these methods should also respect the following rules: - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ The type declaring these methods should also respect the following rules: - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf index 2409297611..344f779af0 100644 --- a/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf +++ b/src/Analyzers/MSTest.Analyzers/xlf/Resources.zh-Hant.xlf @@ -158,8 +158,8 @@ The type declaring these methods should also respect the following rules: - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. - Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. + Synchronously blocking the current thread with 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' inside test methods or test fixtures is a common source of flakiness and can also deadlock when the test framework runs tests on a SynchronizationContext that requires cooperative scheduling. Prefer 'await Task.Delay' for time-based waits and 'await' the task to observe its result. @@ -168,8 +168,8 @@ The type declaring these methods should also respect the following rules: - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code - Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code + Avoid synchronously blocking calls such as 'Thread.Sleep', 'Task.Wait', 'Task.WaitAll', 'Task.WaitAny' or 'Task<TResult>.Result' in test code diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs index 548700599c..4087e0a0f1 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs @@ -4,6 +4,9 @@ using VerifyCS = MSTest.Analyzers.Test.CSharpCodeFixVerifier< MSTest.Analyzers.AvoidThreadSleepAndTaskWaitInTestsAnalyzer, Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; +using VerifyVB = MSTest.Analyzers.Test.VisualBasicCodeFixVerifier< + MSTest.Analyzers.AvoidThreadSleepAndTaskWaitInTestsAnalyzer, + Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; namespace MSTest.Analyzers.UnitTests; @@ -439,4 +442,243 @@ public void TestMethod() await VerifyCS.VerifyAnalyzerAsync(code); } + + [TestMethod] + public async Task ThreadSleepInClassCleanup_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [ClassCleanup] + public static void ClassCleanup() + { + [|Thread.Sleep(100)|]; + } + + [TestMethod] + public void TestMethod() { } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInAssemblyCleanup_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [AssemblyCleanup] + public static void AssemblyCleanup() + { + [|Thread.Sleep(100)|]; + } + + [TestMethod] + public void TestMethod() { } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInGlobalTestInitialize_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public static class MyGlobalHooks + { + [GlobalTestInitialize] + public static void GlobalInit() + { + [|Thread.Sleep(100)|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInGlobalTestCleanup_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public static class MyGlobalHooks + { + [GlobalTestCleanup] + public static void GlobalCleanup() + { + [|Thread.Sleep(100)|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInDerivedTestMethodAttribute_Diagnostic() + { + string code = """ + using System; + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + public sealed class MyCustomTestMethodAttribute : TestMethodAttribute { } + + [TestClass] + public class MyTestClass + { + [MyCustomTestMethod] + public void TestMethod() + { + [|Thread.Sleep(100)|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task TaskWaitAllInTestMethod_Diagnostic() + { + string code = """ + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + Task t1 = Task.CompletedTask; + Task t2 = Task.CompletedTask; + [|Task.WaitAll(t1, t2)|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task TaskWaitAnyInTestMethod_Diagnostic() + { + string code = """ + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() + { + Task t1 = Task.CompletedTask; + Task t2 = Task.CompletedTask; + [|Task.WaitAny(t1, t2)|]; + } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task TaskWaitAllInHelperMethodInTestClass_NoDiagnostic() + { + string code = """ + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + private void Helper() + { + Task t1 = Task.CompletedTask; + Task.WaitAll(t1); + } + + [TestMethod] + public void TestMethod() { } + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInExpressionBodiedTestMethod_Diagnostic() + { + string code = """ + using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class MyTestClass + { + [TestMethod] + public void TestMethod() => [|Thread.Sleep(100)|]; + } + """; + + await VerifyCS.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task ThreadSleepInVisualBasicTestMethod_Diagnostic() + { + string code = """ + Imports System.Threading + Imports Microsoft.VisualStudio.TestTools.UnitTesting + + + Public Class MyTestClass + + Public Sub TestMethod() + [|Thread.Sleep(100)|] + End Sub + End Class + """; + + await VerifyVB.VerifyAnalyzerAsync(code); + } + + [TestMethod] + public async Task TaskOfTResultInVisualBasicTestMethod_Diagnostic() + { + string code = """ + Imports System.Threading.Tasks + Imports Microsoft.VisualStudio.TestTools.UnitTesting + + + Public Class MyTestClass + + Public Sub TestMethod() + Dim t As Task(Of Integer) = Task.FromResult(42) + Dim value As Integer = [|t.Result|] + End Sub + End Class + """; + + await VerifyVB.VerifyAnalyzerAsync(code); + } } From 6d0be7b5b942a0b504b199736599788c63b6358a Mon Sep 17 00:00:00 2001 From: Evangelink <11340282+Evangelink@users.noreply.github.com> Date: Thu, 28 May 2026 14:37:05 +0200 Subject: [PATCH 4/4] Drop unused 'using System;' from derived attribute test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs index 4087e0a0f1..7da98c4068 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/AvoidThreadSleepAndTaskWaitInTestsAnalyzerTests.cs @@ -535,7 +535,6 @@ public static void GlobalCleanup() public async Task ThreadSleepInDerivedTestMethodAttribute_Diagnostic() { string code = """ - using System; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting;