Remarque
L’accès à cette page requiert une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page requiert une autorisation. Vous pouvez essayer de modifier des répertoires.
MSTest fournit un cycle de vie bien défini pour les classes de test et les méthodes de test, ce qui vous permet d’effectuer des opérations d’installation et de destruction à différentes étapes de l’exécution des tests. Comprendre le cycle de vie vous aide à écrire des tests efficaces et à éviter les pièges courants.
Présentation du cycle de vie
Le cycle de vie est divisé en quatre étapes, exécutées du niveau le plus élevé (assemblage) au niveau le plus bas (procédure de test) :
- Niveau assembly : s’exécute une fois lorsque l’assembly de test est chargé et déchargé
- Niveau classe : s’exécute une fois par classe de test
- Niveau de test global : s’exécute avant et après chaque méthode de test dans l’assembly
- Niveau de test : s’exécute pour chaque méthode de test (y compris chaque ligne de données dans les tests paramétrables)
Cycle de vie au niveau de l'assemblage
Les méthodes de cycle de vie d’assembly s’exécutent une fois lorsque l’assembly de test charge et décharge. Utilisez-les pour une configuration ponctuelle coûteuse, comme l’initialisation de base de données ou le démarrage du service.
AssemblyInitialize et AssemblyCleanup
[TestClass]
public class AssemblyLifecycleExample
{
private static IHost? _host;
[AssemblyInitialize]
public static async Task AssemblyInit(TestContext context)
{
// Runs once before any tests in the assembly
_host = await StartTestServerAsync();
context.WriteLine("Test server started");
}
[AssemblyCleanup]
public static async Task AssemblyCleanup(TestContext context)
{
// Runs once after all tests complete
// TestContext parameter available in MSTest 3.8+
if (_host != null)
{
await _host.StopAsync();
}
}
private static Task<IHost> StartTestServerAsync()
{
// Server initialization
return Task.FromResult<IHost>(null!);
}
}
Spécifications
- Les méthodes doivent être
public static - Type de retour :
void,TaskouValueTask(MSTest v3.3+) -
AssemblyInitializenécessite unTestContextparamètre -
AssemblyCleanupaccepte zéro paramètre ou unTestContextparamètre (MSTest 3.8+) - Un seul attribut de chaque type est autorisé par assemblage
- Doit se trouver dans une classe marquée avec
[TestClass]
Conseil / Astuce
Analyseurs associés :
-
MSTEST0012 : valide la
AssemblyInitializesignature. -
MSTEST0013 : valide la
AssemblyCleanupsignature.
Cycle de vie au niveau de la classe
Les méthodes de cycle de vie de classe s’exécutent une fois par classe de test, avant et après toutes les méthodes de test de cette classe. Utilisez-les pour configurer des tests partagés entre les tests d’une classe.
ClassInitialize et ClassCleanup
[TestClass]
public class ClassLifecycleExample
{
private static HttpClient? _client;
[ClassInitialize]
public static void ClassInit(TestContext context)
{
// Runs once before any tests in this class
_client = new HttpClient
{
BaseAddress = new Uri("https://api.example.com")
};
}
[ClassCleanup]
public static void ClassCleanup()
{
// Runs after all tests in this class complete
_client?.Dispose();
}
[TestMethod]
public async Task GetUsers_ReturnsSuccess()
{
HttpResponseMessage response = await _client!.GetAsync("/users");
Assert.IsTrue(response.IsSuccessStatusCode);
}
}
Spécifications
- Les méthodes doivent être
public static - Type de retour :
void,TaskouValueTask(MSTest v3.3+) -
ClassInitializenécessite unTestContextparamètre -
ClassCleanupaccepte zéro paramètre ou unTestContextparamètre (MSTest 3.8+) - Un seul attribut autorisé par classe
Comportement d’héritage
Contrôler si ClassInitialize s'exécute pour les classes dérivées à l'aide de InheritanceBehavior:
[TestClass]
public class BaseTestClass
{
[ClassInitialize(InheritanceBehavior.BeforeEachDerivedClass)]
public static void BaseClassInit(TestContext context)
{
// Runs before each derived class's tests
}
}
[TestClass]
public class DerivedTestClass : BaseTestClass
{
[TestMethod]
public void DerivedTest()
{
// BaseClassInit runs before this class's tests
}
}
| InheritanceBehavior | Descriptif |
|---|---|
None (valeur par défaut) |
Initialiser uniquement les processus de la classe déclarée |
BeforeEachDerivedClass |
Initialiser les lancements avant chaque classe dérivée |
Conseil / Astuce
Analyseurs associés :
-
MSTEST0010 : valide la
ClassInitializesignature. -
MSTEST0011 : valide la
ClassCleanupsignature. -
MSTEST0034 - recommande d’utiliser
ClassCleanupBehavior.EndOfClass.
Cycle de vie au niveau du test global
Remarque
Les attributs de cycle de vie des tests globaux ont été introduits dans MSTest 3.10.0.
Les méthodes de cycle de vie des tests globaux s’exécutent avant et après chaque méthode de test dans l’ensemble de l’assembly, sans avoir à ajouter du code à chaque classe de test.
GlobalTestInitialize et GlobalTestCleanup
[TestClass]
public class GlobalTestLifecycleExample
{
[GlobalTestInitialize]
public static void GlobalTestInit(TestContext context)
{
// Runs before every test method in the assembly
context.WriteLine($"Starting test: {context.TestName}");
}
[GlobalTestCleanup]
public static void GlobalTestCleanup(TestContext context)
{
// Runs after every test method in the assembly
context.WriteLine($"Finished test: {context.TestName}");
}
}
Spécifications
- Les méthodes doivent être
public static - Type de retour :
void,TaskouValueTask - Doit avoir exactement un
TestContextparamètre - Doit se trouver dans une classe marquée avec
[TestClass] - Plusieurs méthodes avec ces attributs sont autorisées dans l’assembly
Remarque
Lorsqu’il existe plusieurs méthodes GlobalTestInitialize ou GlobalTestCleanup, l’ordre d’exécution n’est pas garanti. Ce TimeoutAttribute n’est pas pris en charge sur les méthodes GlobalTestInitialize.
Conseil / Astuce
Analyseur associé : MSTEST0050 - valide les méthodes globales des appareils de test.
Cycle de vie au niveau du test
Le cycle de vie au niveau du test s’exécute pour chaque méthode de test. Pour les tests paramétrables, le cycle de vie s’exécute pour chaque ligne de données.
Phase de configuration
Utiliser TestInitialize ou un constructeur pour la configuration par test :
[TestClass]
public class TestLevelSetupExample
{
private Calculator? _calculator;
public TestLevelSetupExample()
{
// Constructor runs before TestInitialize
// Use for simple synchronous initialization
}
[TestInitialize]
public async Task TestInit()
{
// Runs before each test method
// Supports async, attributes like Timeout
_calculator = new Calculator();
await _calculator.InitializeAsync();
}
[TestMethod]
public void Add_TwoNumbers_ReturnsSum()
{
int result = _calculator!.Add(2, 3);
Assert.AreEqual(5, result);
}
}
Constructeur et TestInitialize :
| Aspect | Constructeur | TestInitialize |
|---|---|---|
| Prise en charge asynchrone | Non | Oui |
| Gestion du délai d’expiration | Non | Oui (avec [Timeout] attribut) |
| Ordre d’exécution | Premier | Après le constructeur |
| Héritage | Base puis dérivée | Base puis dérivée |
| Comportement des exceptions | Nettoyage et Disponibilisation ne s’exécutent pas (aucune instance n’existe) | Nettoyage et désallocation continuent d'être exécutés |
Conseil / Astuce
Quelle approche dois-je utiliser ? Les constructeurs sont généralement préférés, car ils vous permettent d'utiliser readonly champs, ce qui applique l'immuabilité et rend votre classe de test plus facile à comprendre. Utilisez TestInitialize quand vous avez besoin d’une initialisation asynchrone ou d’une prise en charge du délai d’expiration.
Vous pouvez également combiner les deux approches : utilisez le constructeur pour l’initialisation synchrone simple des readonly champs et TestInitialize pour une configuration asynchrone supplémentaire qui dépend de ces champs.
Vous pouvez éventuellement activer les analyseurs de code pour appliquer une approche cohérente :
- MSTEST0019 - Préférer les méthodes TestInitialize aux constructeurs
- MSTEST0020 - Préférer les constructeurs aux méthodes TestInitialize
Phase d’exécution
La méthode de test s’exécute une fois l’installation terminée. Pour les méthodes de test async, MSTest attend le retour de Task ou ValueTask.
Avertissement
Par défaut, les méthodes de test asynchrones n’ont pas de SynchronizationContext. Cela ne s’applique pas aux UITestMethod tests dans UWP et WinUI, qui s’exécutent sur le thread d’interface utilisateur.
Phase de nettoyage
Utilisez TestCleanup ou IDisposable/IAsyncDisposable pour le nettoyage par test :
[TestClass]
public class TestLevelCleanupExample
{
private HttpClient? _client;
[TestInitialize]
public void TestInit()
{
_client = new HttpClient();
}
[TestCleanup]
public void TestCleanup()
{
if (_client != null)
{
_client.Dispose();
}
}
[TestMethod]
public async Task GetData_ReturnsSuccess()
{
HttpResponseMessage response = await _client!.GetAsync("https://example.com");
Assert.IsTrue(response.IsSuccessStatusCode);
}
}
Ordre d’exécution du nettoyage (dérivé de la base) :
-
TestCleanup(classe dérivée) -
TestCleanup(classe de base) -
DisposeAsync(en cas d’implémentation) -
Dispose(en cas d’implémentation)
Conseil / Astuce
Vous pouvez éventuellement activer les analyseurs de code pour appliquer une approche de nettoyage cohérente :
- MSTEST0021 - Préférer supprimer les méthodes TestCleanup
- MSTEST0022 - Préférer TestCleanup aux méthodes Dispose
Si vous avez activé des analyseurs non MSTest, tels que des règles d’analyse de code .NET, vous pouvez voir CA1001 suggérer d’implémenter le modèle de suppression lorsque votre classe de test possède des ressources jetables. Ce comportement est attendu et vous devez suivre les instructions de l’analyseur.
Terminer l’ordre de niveau test
- Créer une instance de classe de test (constructeur)
- Définir la propriété
TestContext(si elle est présente) - Exécuter les méthodes
GlobalTestInitialize - Exécuter les méthodes
TestInitialize(de la base à la dérivée) - Exécuter la méthode de test
- Mettre à jour
TestContextavec les résultats (par exemple, la propriétéOutcome) - Exécuter des
TestCleanupméthodes (dérivées de la base) - Exécuter les méthodes
GlobalTestCleanup - Exécuter
DisposeAsync(s’il est implémenté) - Exécuter
Dispose(s’il est implémenté)
Conseil / Astuce
Analyseurs associés :
-
MSTEST0008 : valide la
TestInitializesignature. -
MSTEST0009 : valide la
TestCleanupsignature. - MSTEST0063 : valide le constructeur de classe de test.
Meilleures pratiques
Utilisez l’étendue appropriée : placez la configuration au niveau le plus élevé qui est logique pour éviter le travail redondant.
Maintenir le programme d’installation rapide : la configuration longue affecte tous les tests. Envisagez l’initialisation différée pour les ressources coûteuses.
Nettoyer correctement : nettoyez toujours les ressources pour éviter les interférences de test et les fuites de mémoire.
Gérez correctement l'asynchrone : utilisez des types de retour , et non
async Task, pour les méthodes de cycle de vie asynchrones.Envisagez l’isolation des tests : chaque test doit être indépendant. Évitez l’état mutable partagé entre les tests.
Utilisez GlobalTest avec parcimonie : les méthodes de cycle de vie globales s’exécutent pour chaque test, de sorte qu’elles restent légères.