195 votes

Exécuter les tests unitaires en série (plutôt qu'en parallèle)

J'essaie de tester à l'unité un moteur de gestion d'hôte WCF que j'ai écrit. Le moteur crée essentiellement des instances ServiceHost à la volée sur la base de la configuration. Cela nous permet de reconfigurer dynamiquement les services disponibles sans avoir à les arrêter et à les redémarrer à chaque fois qu'un nouveau service est ajouté ou qu'un ancien est supprimé.

J'ai rencontré une difficulté dans le test unitaire de ce moteur de gestion d'hôte, cependant, en raison de la façon dont ServiceHost fonctionne. Si un ServiceHost a déjà été créé, ouvert et n'a pas encore été fermé pour un point de terminaison particulier, un autre ServiceHost pour le même point de terminaison ne peut pas être créé, ce qui entraîne une exception. Étant donné que les plateformes modernes de tests unitaires parallélisent l'exécution des tests, je n'ai aucun moyen efficace de tester ce morceau de code.

J'ai utilisé xUnit.NET, en espérant qu'en raison de son extensibilité, je pourrais trouver un moyen de le forcer à exécuter les tests en série. Cependant, je n'ai pas eu de chance. J'espère que quelqu'un ici sur SO a rencontré un problème similaire et sait comment faire pour que les tests unitaires s'exécutent en série.

NOTE : ServiceHost est une classe WCF, écrite par Microsoft. Je n'ai pas la possibilité de modifier son comportement. Héberger chaque point d'extrémité de service une seule fois est également le bon comportement... cependant, ce n'est pas particulièrement propice aux tests unitaires.

290voto

Abhinav Saxena Points 541

Chaque classe de test est une collection de tests unique et les tests qu'elle contient s'exécutent en séquence. Ainsi, si vous placez tous vos tests dans la même collection, ils s'exécuteront de manière séquentielle.

Dans xUnit, vous pouvez effectuer les changements suivants pour y parvenir :

Les suivants se dérouleront en parallèle :

namespace IntegrationTests
{
    public class Class1
    {
        [Fact]
        public void Test1()
        {
            Console.WriteLine("Test1 called");
        }

        [Fact]
        public void Test2()
        {
            Console.WriteLine("Test2 called");
        }
    }

    public class Class2
    {
        [Fact]
        public void Test3()
        {
            Console.WriteLine("Test3 called");
        }

        [Fact]
        public void Test4()
        {
            Console.WriteLine("Test4 called");
        }
    }
}

Pour le rendre séquentiel, il suffit de placer les deux classes de test dans la même collection :

namespace IntegrationTests
{
    [Collection("Sequential")]
    public class Class1
    {
        [Fact]
        public void Test1()
        {
            Console.WriteLine("Test1 called");
        }

        [Fact]
        public void Test2()
        {
            Console.WriteLine("Test2 called");
        }
    }

    [Collection("Sequential")]
    public class Class2
    {
        [Fact]
        public void Test3()
        {
            Console.WriteLine("Test3 called");
        }

        [Fact]
        public void Test4()
        {
            Console.WriteLine("Test4 called");
        }
    }
}

Pour plus d'informations, vous pouvez consulter ce lien

140voto

Squiggle Points 1269

Important : cette réponse s'applique à .NET Framework. Pour dotnet core, voir la réponse de Dimitry à propos de xunit.runner.json .

Tous les bons tests unitaires doivent être isolés à 100 %. L'utilisation d'un état partagé (par exemple, dépendant d'un static qui est modifiée par chaque test) est considérée comme une mauvaise pratique.

Cela dit, votre question sur l'exécution séquentielle des tests xUnit a une réponse ! J'ai rencontré exactement le même problème parce que mon système utilise un localisateur de service statique (ce qui est loin d'être idéal).

Par défaut, xUnit 2.x exécute tous les tests en parallèle. Ceci peut être modifié pour chaque assemblage en définissant l'option CollectionBehavior dans le fichier AssemblyInfo.cs de votre projet de test.

Pour l'utilisation de la séparation par assemblage :

using Xunit;
[assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)]

ou pour ne pas utiliser du tout la parallélisation :

[assembly: CollectionBehavior(DisableTestParallelization = true)]

Ce dernier est probablement celui que vous souhaitez. Plus d'informations sur la parallélisation et la configuration peuvent être trouvées sur le site web de la Documentation xUnit .

130voto

Dmitry Polomoshnov Points 1915

Pour les projets .NET Core, créez xunit.runner.json avec :

{
  "parallelizeAssembly": false,
  "parallelizeTestCollections": false
}

En outre, votre csproj doit contenir

<ItemGroup>
  <None Update="xunit.runner.json"> 
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

Pour les anciens projets .Net Core, votre project.json doit contenir

"buildOptions": {
  "copyToOutput": {
    "include": [ "xunit.runner.json" ]
  }
}

34voto

Mark Amery Points 4705

Pour les projets .NET Core, vous pouvez configurer xUnit avec un fichier xunit.runner.json comme indiqué à l'adresse suivante https://xunit.net/docs/configuration-files .

Le paramètre que vous devez modifier pour arrêter l'exécution parallèle des tests est le suivant parallelizeTestCollections qui est par défaut true :

Régler ce paramètre sur true si l'assemblée est disposée à exécuter des tests en parallèle à l'intérieur de cette assemblée les uns par rapport aux autres. ... Définir cette valeur à false pour désactiver toute parallélisation au sein de cet ensemble de test.

Type de schéma JSON : booléen
Valeur par défaut : true

Ainsi, un minimum de xunit.runner.json à cette fin se présente comme suit

{
    "parallelizeTestCollections": false
}

Comme indiqué dans la documentation, n'oubliez pas d'inclure ce fichier dans votre compilation, soit par :

  • Paramètres Copier dans le répertoire de sortie à Copier si plus récent dans le fichier Propriétés dans Visual Studio, ou

  • Ajout

      <Content Include=".\xunit.runner.json">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </Content>

    à votre .csproj ou

  • Ajout

      "buildOptions": {
        "copyToOutput": {
          "include": [ "xunit.runner.json" ]
        }
      }

    à votre project.json fichier

en fonction du type de projet.

Enfin, en plus à ce qui précède, si vous utilisez Visual Studio, assurez-vous que vous n'avez pas accidentellement cliqué sur le bouton Exécuter des tests en parallèle qui entraînera l'exécution des tests en parallèle même si vous avez désactivé la parallélisation dans le fichier xunit.runner.json . Les concepteurs de l'interface utilisateur de Microsoft ont astucieusement fait en sorte que ce bouton ne soit pas étiqueté, qu'il soit difficile à remarquer et qu'il se trouve à environ un centimètre de l'écran d'accueil. "Exécutez tout" dans l'Explorateur de tests, afin de maximiser les chances que vous le cliquiez par erreur et que vous n'ayez aucune idée de la raison pour laquelle vos tests échouent soudainement :

Screenshot with the button circled

24voto

C'est une vieille question mais je voulais écrire une solution pour les gens qui cherchent depuis peu comme moi :)

Remarque : J'utilise cette méthode dans les tests d'intégration de Dot Net Core WebUI avec xunit version 2.4.1.

Créez une classe vide nommée NonParallelCollectionDefinitionClass et donnez ensuite CollectionDefinition à

using Xunit;

namespace WebUI.IntegrationTests.Common
{
    [CollectionDefinition("Non-Parallel Collection", DisableParallelization = true)]
    public class NonParallelCollectionDefinitionClass
    {
    }
}

A

namespace WebUI.IntegrationTests.Controllers.Users
{
    [Collection("Non-Parallel Collection")]
    public class ChangePassword : IClassFixture<CustomWebApplicationFactory<Startup>>
    ...

W

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X