Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
IntelliTest génère des entrées pour les tests unitaires paramétrables en analysant les conditions de branche dans le programme. Les entrées de test sont choisies en fonction de la possibilité de déclencher de nouveaux comportements de branchement du programme. L’analyse est un processus incrémentiel. Il affine un prédicat q: I -> {true, false} sur les paramètres Id’entrée de test formels.
q représente l’ensemble des comportements que IntelliTest a déjà observés. Initialement, q := false puisque rien n’a encore été observé.
Les étapes de la boucle sont les suivantes :
IntelliTest détermine les entrées
iafin queq(i)=false, en utilisant un solveur de contraintes. Par construction, l’entréeiprend un chemin d’exécution non vu précédemment. Au départ, cela signifie qu’ilipeut s’agir de n’importe quelle entrée, car aucun chemin d’exécution n’a encore été découvert.IntelliTest exécute le test avec l’entrée
ichoisie et surveille l’exécution du test et du programme en cours de test.Pendant l’exécution, le programme prend un chemin particulier déterminé par toutes les branches conditionnelles du programme. L’ensemble de toutes les conditions qui déterminent l’exécution est appelé la condition de chemin d’accès, écrite en tant que prédicat
p: I -> {true, false}sur les paramètres d’entrée formels. IntelliTest calcule une représentation de ce prédicat.IntelliTest sets
q := (q or p). En d’autres termes, il enregistre le fait qu’il a vu le chemin représenté parp.Passez à l’étape 1.
Le solveur de contrainte d’IntelliTest peut traiter les valeurs de tous les types qui peuvent apparaître dans les programmes .NET :
IntelliTest filtre les entrées qui violent les hypothèses indiquées.
Outre les entrées immédiates (arguments pour les tests unitaires paramétrables), un test peut dessiner d’autres valeurs d’entrée à partir de la classe statique PexChoose . Les choix déterminent également le comportement des simulations paramétrables.
Solveur de contraintes
IntelliTest utilise un solveur de contraintes pour déterminer les valeurs d’entrée pertinentes d’un test et le programme sous test.
IntelliTest utilise le solveur de contrainte Z3 .
Couverture dynamique du code
En tant qu’effet secondaire de la surveillance du runtime, IntelliTest collecte des données de couverture de code dynamiques. Cela est appelé dynamique , car IntelliTest connaît uniquement le code qui a été exécuté, par conséquent, il ne peut pas donner des valeurs absolues pour la couverture de la même façon que d’autres outils de couverture généralement.
Par exemple, lorsque IntelliTest signale la couverture dynamique sous la forme de blocs de base 5/10, cela signifie que cinq blocs sur dix ont été couverts, où le nombre total de blocs dans toutes les méthodes atteintes jusqu’à présent par l’analyse (par opposition à toutes les méthodes qui existent dans l’assembly sous test) est de dix. Plus loin dans l’analyse, étant donné que des méthodes plus accessibles sont découvertes, le numérateur (5 dans cet exemple) et le dénominateur (10) peuvent augmenter.
Entiers et nombres à virgule flottante
Le solveur de contrainte d’IntelliTest détermine les valeurs d’entrée de test des types primitifs tels que byte, int, float et d’autres afin de déclencher différents chemins d’exécution pour le test et le programme testé.
Objets
IntelliTest peut créer des instances de classes .NET existantes, ou vous pouvez utiliser IntelliTest pour créer automatiquement des objets fictifs qui implémentent une interface spécifique et se comportent de différentes manières en fonction de l’utilisation.
Instancier des classes existantes
Quel est le problème?
IntelliTest surveille les instructions exécutées lors de l’exécution d’un test et du programme sous test. En particulier, il surveille tous les accès aux champs. Il utilise ensuite un solveur de contrainte pour déterminer les nouvelles entrées de test, y compris les objets et leurs valeurs de champ, de sorte que le test et le programme sous test se comportent de différentes façons intéressantes.
Cela signifie que IntelliTest doit créer des objets de certains types et définir leurs valeurs de champ. Si la classe est visible et a un constructeur par défaut visible , IntelliTest peut créer une instance de la classe. Si tous les champs de la classe sont visibles, IntelliTest peut définir automatiquement les champs.
Si le type n’est pas visible ou que les champs ne sont pas visibles, IntelliTest a besoin d’aide pour créer des objets et les amener dans des états intéressants afin d’obtenir une couverture de code maximale. IntelliTest peut utiliser la réflexion pour créer et initialiser des instances de manière arbitraire, mais cela n’est généralement pas souhaitable, car il peut amener l’objet dans un état qui ne peut jamais se produire pendant l’exécution normale du programme. Au lieu de cela, IntelliTest s’appuie sur des indicateurs de l’utilisateur.
Visibilité
.NET a un modèle de visibilité élaboré : types, méthodes, champs et autres membres peuvent être privés, publics, internes, etc.
Lorsque IntelliTest génère des tests, il tente d’effectuer uniquement des actions (telles que les constructeurs, méthodes et champs de définition) qui sont légales en ce qui concerne les règles de visibilité .NET à partir du contexte des tests générés.
Les règles sont les suivantes :
Visibilité des membres internes
- IntelliTest part du principe que les tests générés auront accès aux membres internes visibles par PexClass englobant. .NET a InternalsVisibleToAttribute pour étendre la visibilité des membres internes à d'autres assemblies.
Visibilité des membres privés et familiaux (protégés en C#) du PexClass
- IntelliTest place toujours les tests générés directement dans pexClass ou dans une sous-classe. Par conséquent, IntelliTest suppose qu’il peut utiliser tous les membres de la famille visibles (protégés en C#).
- Si les tests générés sont placés directement dans pexClass (généralement à l’aide de classes partielles), IntelliTest suppose qu’il peut également utiliser tous les membres privés de PexClass.
Visibilité des membres publics
- IntelliTest part du principe qu’il peut utiliser tous les membres exportés visibles dans le contexte de PexClass.
Simulations paramétrables
Comment tester une méthode qui a un paramètre d’un type d’interface ? Ou d’une classe non scellée ? IntelliTest ne sait pas quelles implémentations seront utilisées ultérieurement lorsque cette méthode est appelée. Et peut-être qu’il n’y a même pas d’implémentation réelle disponible au moment du test.
La réponse conventionnelle consiste à utiliser des objets fictifs avec un comportement explicite.
Un objet fictif implémente une interface (ou étend une classe non scellée). Il ne représente pas une implémentation réelle, mais simplement un raccourci qui permet l’exécution de tests à l’aide de l’objet fictif. Son comportement est défini manuellement dans chaque cas de test où il est utilisé. De nombreux outils existent qui facilitent la définition d’objets fictifs et leur comportement attendu, mais ce comportement doit toujours être défini manuellement.
Au lieu de valeurs codées en dur dans des objets fictifs, IntelliTest peut générer les valeurs. Tout comme il active les tests unitaires paramétrables, IntelliTest active également les simulations paramétrables.
Les maquettes paramétrables ont deux modes d’exécution différents :
- choix : lors de l’exploration du code, les simulations paramétrables sont une source d’entrées de test supplémentaires, et IntelliTest tente de choisir des valeurs intéressantes
- relecture : lors de l’exécution d’un test généré précédemment, les simulations paramétrables se comportent comme des stubs avec un comportement (en d’autres termes, comportement prédéfini).
Utilisez PexChoose pour obtenir des valeurs pour les mocks paramétrés.
Structures
Le raisonnement d’IntelliTest sur les valeurs de struct est similaire à la façon dont il traite les objets.
Tableaux et chaînes
IntelliTest surveille les instructions exécutées lors de l’exécution d’un test et du programme sous test. En particulier, il observe quand le programme dépend de la longueur d’une chaîne ou d’un tableau (et les limites et longueurs inférieures d’un tableau multidimensionnel). Il observe également comment le programme utilise les différents éléments d’une chaîne ou d’un tableau. Il utilise ensuite un solveur de contrainte pour déterminer quelles longueurs et valeurs d’élément pourraient influencer le comportement du test et du programme testé de manière remarquable.
IntelliTest tente de réduire la taille des tableaux et des chaînes nécessaires pour déclencher des comportements de programme intéressants.
Obtenir des entrées supplémentaires
La classe statique PexChoose peut être utilisée pour obtenir des entrées supplémentaires dans un test et peut être utilisée pour implémenter des simulations paramétrables.
Vous avez des commentaires ?
Publiez vos idées et demandes de fonctionnalités sur la Communauté des développeurs.