J’essaie de tester à l’unité le moteur de gestion d’hôte WCF que j’ai écrit. Le moteur crée essentiellement des instances ServiceHost à la volée en fonction de la configuration. Cela nous permet de reconfigurer de manière dynamic les services disponibles sans avoir à les supprimer et à les redémarrer chaque fois qu’un nouveau service est ajouté ou un ancien supprimé.
J’ai rencontré une difficulté lors des tests unitaires de ce moteur de gestion d’hôte, en raison du fonctionnement de ServiceHost. Si un ServiceHost a déjà été créé, ouvert et pas encore fermé pour un noeud final particulier, un autre ServiceHost pour le même noeud final ne peut pas être créé, ce qui entraîne une exception. Étant donné que les plates-formes de tests unitaires modernes parallélisent leur exécution, je ne dispose d’aucun moyen efficace pour tester ce morceau de code.
J’ai utilisé xUnit.NET, espérant pouvoir, à cause de son extensibilité, 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 sur SO a rencontré un problème similaire et sait comment exécuter les tests unitaires en série.
REMARQUE: ServiceHost est une classe WCF, écrite par Microsoft. Je n’ai pas la capacité de changer son comportement. Le comportement approprié de chaque sharepoint terminaison de service est également approprié … Toutefois, il n’est pas particulièrement propice aux tests unitaires.
Comme indiqué ci-dessus, tous les bons tests unitaires doivent être isolés à 100%. L’utilisation de l’état partagé (par exemple, en fonction d’une propriété static
modifiée par chaque test) est considérée comme une mauvaise pratique.
Cela dit, votre question sur l’exécution séquentielle de tests xUnit a une réponse! J’ai rencontré exactement le même problème car mon système utilise un localisateur de services statique (ce qui est moins qu’idéal).
Par défaut, xUnit 2.x exécute tous les tests en parallèle. Cela peut être modifié par assemblage en définissant CollectionBehavior
dans votre AssemblyInfo.cs de votre projet de test.
Pour la séparation par assemblage, utilisez:
using Xunit; [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)]
ou pour aucune parallélisation du tout utiliser:
[assembly: CollectionBehavior(DisableTestParallelization = true)]
Ce dernier est probablement celui que vous voulez. Vous trouverez plus d’informations sur la parallélisation et la configuration dans la documentation de xUnit .
Pour les projets .NET Core, créez xunit.runner.json
avec:
{ "parallelizeAssembly": false, "parallelizeTestCollections": false }
De plus, votre project.json
devrait contenir
"buildOptions": { "copyToOutput": { "include": [ "xunit.runner.json" ] } }
Chaque classe de test constitue une collection de tests unique. Les tests correspondants s’exécutent en séquence. Par conséquent, si vous placez tous vos tests dans la même collection, ils seront exécutés de manière séquentielle.
Dans xUnit, vous pouvez apporter les modifications suivantes pour y parvenir:
La suite suivra 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 vous 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 vous référer à ce lien
Pour les projets .NET Core, vous pouvez configurer xUnit avec un fichier xunit.runner.json
, comme xunit.runner.json
à l’ adresse https://xunit.github.io/docs/configuring-with-json.html .
Le paramètre que vous devez modifier pour arrêter l’exécution du test en parallelizeTestCollections
est parallelizeTestCollections
, dont la valeur par défaut est true
:
Définissez cette propriété sur
true
si l’assemblage souhaite exécuter des tests dans cet assemblage en parallèle les uns par rapport aux autres. … Affectez la valeurfalse
à cettefalse
pour désactiver toute la parallélisation dans cet assemblage de test.Type de schéma JSON: booléen
Valeur par défaut:true
Donc, un xunit.runner.json
minimal à cette fin ressemble à
{ "parallelizeTestCollections": false }
Comme indiqué dans la documentation, n’oubliez pas d’inclure ce fichier dans votre construction, en:
Ajouter
PreserveNewest
dans votre fichier .csproj
, ou
Ajouter
"buildOptions": { "copyToOutput": { "include": [ "xunit.runner.json" ] } }
dans votre fichier project.json
en fonction de votre type de projet.
Enfin, en plus de ce qui précède, si vous utilisez Visual Studio, assurez-vous de ne pas avoir cliqué par inadvertance sur le bouton Exécuter les tests en parallèle , ce qui entraînera l’exécution des tests en parallèle, même si vous avez désactivé la parallélisation dans xunit.runner.json
. Les concepteurs d’interface utilisateur de Microsoft ont habilement fait en sorte que ce bouton ne soit pas étiqueté, difficile à remarquer et à environ un centimètre du bouton “Run All” (Exécuter tout) de Test Explorer, afin de maximiser les chances que vous le frappiez par erreur et que vous ne sachiez pas pourquoi vos tests échouent soudainement:
vous pouvez utiliser la playlist
clic droit sur la méthode de test -> Ajouter à la playlist -> Nouvelle playlist
alors vous pouvez spécifier l’ordre d’exécution, la valeur par défaut est, lorsque vous les ajoutez à la liste de lecture, mais vous pouvez modifier le fichier de liste de lecture à votre guise
Je ne connais pas les détails, mais il semblerait que vous essayiez peut-être de faire des tests d’intégration plutôt que des tests unitaires . Si vous pouviez isoler la dépendance à l’égard de ServiceHost
, vos tests seraient probablement plus faciles (et plus rapides). Donc, par exemple, vous pouvez tester indépendamment les éléments suivants:
IServiceHostFactory
et une IConfiguration
Les outils permettant d’inclure des structures d’isolation (mocking) et (éventuellement) des conteneurs IoC. Voir:
Peut-être que vous pouvez utiliser les tests unitaires avancés . Il vous permet de définir la séquence dans laquelle vous exécutez le test . Vous devrez donc peut-être créer un nouveau fichier cs pour héberger ces tests.
Voici comment vous pouvez combiner les méthodes de test pour qu’elles fonctionnent dans l’ordre que vous souhaitez.
[Test] [Sequence(16)] [Requires("POConstructor")] [Requires("WorkOrderConstructor")] public void ClosePO() { po.Close(); // one charge slip should be added to both work orders Assertion.Assert(wo1.ChargeSlipCount==1, "First work order: ChargeSlipCount not 1."); Assertion.Assert(wo2.ChargeSlipCount==1, "Second work order: ChargeSlipCount not 1."); ... }
Faites-moi savoir si cela fonctionne.