Qt Test Meilleures pratiques
Nous vous recommandons d'ajouter des tests Qt Test pour les corrections de bogues et les nouvelles fonctionnalités. Avant d'essayer de corriger un bogue, ajoutez un test de régression (idéalement automatique) qui échoue avant la correction, présentant le bogue, et qui réussit après la correction. Lorsque vous développez de nouvelles fonctionnalités, ajoutez des tests pour vérifier qu'elles fonctionnent comme prévu.
Le respect d'un ensemble de normes de codage permettra aux tests automatiques de Qt de fonctionner de manière plus fiable dans tous les environnements. Par exemple, certains tests doivent lire des données à partir d'un disque. Si aucune norme n'est établie sur la manière de procéder, certains tests ne seront pas portables. Par exemple, un test qui suppose que ses fichiers de données de test se trouvent dans le répertoire de travail actuel ne fonctionne que pour une compilation in-source. Dans une compilation parallèle (en dehors du répertoire source), le test ne parviendra pas à trouver ses données.
Les sections suivantes contiennent des lignes directrices pour l'écriture des tests Qt :
- Principes généraux
- Écrire des tests fiables
- Améliorer la sortie des tests
- Écrire du code testable
- Mise en place de machines de test
Principes généraux
Les sections suivantes fournissent des lignes directrices générales pour l'écriture de tests unitaires :
- Vérifier les tests
- Donner aux fonctions de test des noms descriptifs
- Écrire des fonctions de test autonomes
- Tester la pile complète
- Faire en sorte que les tests soient terminés rapidement
- Utiliser des tests basés sur les données
- Utiliser des outils de couverture
- Sélectionner les mécanismes appropriés pour exclure les tests
- Éviter Q_ASSERT
Vérifier les tests
Ecrivez et livrez vos tests avec votre correction ou votre nouvelle fonctionnalité sur une nouvelle branche. Une fois que vous avez terminé, vous pouvez extraire la branche sur laquelle votre travail est basé, et extraire dans cette branche les fichiers de test pour vos nouveaux tests. Cela vous permet de vérifier que les tests échouent bien sur la branche précédente, et donc qu'ils détectent bien un bogue ou qu'ils testent bien une nouvelle fonctionnalité.
Par exemple, le flux de travail pour corriger un bogue dans la classe QDateTime pourrait être le suivant si vous utilisez le système de contrôle de version Git :
- Créez une branche pour votre correction et votre test :
git checkout -b fix-branch 5.14 - Écrivez un test et corrigez le bogue.
- Construisez et testez à la fois la correction et le nouveau test, pour vérifier que le nouveau test passe avec la correction.
- Ajoutez la correction et le test à votre branche :
git add tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp src/corelib/time/qdatetime.cpp - Livrez le correctif et le test à votre branche :
git commit -m 'Fix bug in QDateTime' - Pour vérifier que le test attrape effectivement quelque chose pour lequel vous aviez besoin du correctif, vérifiez la branche sur laquelle vous avez basé votre propre branche :
git checkout 5.14 - Ne téléchargez que le fichier de test sur la branche 5.14 :
git checkout fix-branch -- tests/auto/corelib/time/qdatetime/tst_qdatetime.cppSeul le test est maintenant sur la branche de correction. Le reste de l'arbre des sources est toujours sur la branche 5.14.
- Construisez et exécutez le test pour vérifier qu'il échoue sur la branche 5.14, et donc qu'il détecte bien un bogue.
- Vous pouvez maintenant retourner à la branche fix :
git checkout fix-branch - Alternativement, vous pouvez restaurer votre arbre de travail à un état propre sur 5.14 :
git checkout HEAD -- tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
Lorsque vous examinez une modification, vous pouvez adapter ce flux de travail pour vérifier que la modification est bien accompagnée d'un test pour un problème qu'elle corrige.
Donner aux fonctions de test des noms descriptifs
Il est important de nommer les cas de test. Le nom du test apparaît dans le rapport d'échec d'un test. Pour les tests basés sur des données, le nom de la ligne de données apparaît également dans le rapport d'échec. Les noms donnent à ceux qui lisent le rapport une première indication de ce qui n'a pas fonctionné.
Les noms des fonctions de test doivent indiquer clairement ce que la fonction essaie de tester. N'utilisez pas simplement l'identifiant du bug-tracking, car les identifiants deviennent obsolètes si le bug-tracker est remplacé. De plus, certains systèmes de suivi des bogues peuvent ne pas être accessibles à tous les utilisateurs. Lorsque le rapport de bogue peut présenter un intérêt pour les lecteurs ultérieurs du code de test, vous pouvez le mentionner dans un commentaire à côté d'une partie pertinente du test.
De même, lorsque vous écrivez des tests axés sur les données, donnez des noms descriptifs aux cas de test, qui indiquent l'aspect de la fonctionnalité sur lequel chacun se concentre. Ne vous contentez pas de numéroter les cas de test ou d'utiliser des identifiants de suivi des bogues. Une personne lisant le résultat du test n'aura aucune idée de la signification des nombres ou des identifiants. Vous pouvez ajouter un commentaire sur la ligne de test qui mentionne l'identifiant de suivi des bogues, le cas échéant. Il est préférable d'éviter les caractères d'espacement et les caractères qui peuvent être significatifs pour les shells de ligne de commande sur lesquels vous souhaitez exécuter des tests. Cela facilite la spécification du test et de l'étiquette sur la ligne de commande de votre programme de test - par exemple, pour limiter l'exécution d'un test à un seul cas de test.
Écrire des fonctions de test autonomes
Dans un programme de test, les fonctions de test doivent être indépendantes les unes des autres et ne doivent pas dépendre de l'exécution de fonctions de test précédentes. Vous pouvez le vérifier en exécutant la fonction de test de manière autonome à l'aide de tst_foo testname.
Ne réutilisez pas les instances de la classe testée dans plusieurs tests. Les instances de test (par exemple les widgets) ne doivent pas être des variables membres des tests, mais doivent de préférence être instanciées sur la pile pour garantir un nettoyage correct même si un test échoue, afin que les tests n'interfèrent pas les uns avec les autres.
Si votre test implique des modifications globales, veillez à ce que l'état antérieur soit restauré à la fin du test, qu'il réussisse ou qu'il échoue. Puisque l'échec empêche le code postérieur à la vérification défaillante de s'exécuter, la restauration à la fin du test ne fonctionne pas lorsque le test échoue. La manière la plus robuste de restaurer même en cas d'échec est d'instancier un objet RAII dont le destructeur restaure l'état antérieur. Cela peut souvent être fait de manière pratique en utilisant qScopeGuard, par exemple
const auto restoreDefaultLocale = qScopeGuard([prior = QLocale()]() { QLocale::setDefault(prior); });
avant le premier appel à QLocale::setDefault() dans un test qui doit contrôler la locale utilisée par le code testé.
Tester la pile complète
Si une API est implémentée en termes de backends enfichables ou spécifiques à une plateforme qui font le gros du travail, assurez-vous d'écrire des tests qui couvrent les chemins de code jusqu'aux backends. Tester les parties de l'API de la couche supérieure à l'aide d'un backend fictif est un bon moyen d'isoler les erreurs de la couche API des backends, mais il est complémentaire des tests qui exécutent l'implémentation réelle avec des données réelles.
Faire en sorte que les tests se terminent rapidement
Les tests ne doivent pas perdre de temps en étant inutilement répétitifs, en utilisant des volumes de données de test trop importants ou en introduisant des temps morts inutiles.
C'est particulièrement vrai pour les tests unitaires, où chaque seconde supplémentaire d'exécution des tests unitaires allonge la durée des tests CI d'une branche sur plusieurs cibles. N'oubliez pas que les tests unitaires sont distincts des tests de charge et de fiabilité, pour lesquels on s'attend à des volumes de données de test plus importants et à des exécutions de test plus longues.
Les tests de référence, qui exécutent généralement le même test plusieurs fois, doivent être situés dans un répertoire tests/benchmarks distinct et ne doivent pas être mélangés avec les tests unitaires fonctionnels.
Utiliser des tests pilotés par les données
Lestests pilotés par les données facilitent l'ajout de nouveaux tests pour les conditions limites trouvées dans les rapports de bogues ultérieurs.
L'utilisation d'un test piloté par les données plutôt que de tester plusieurs éléments en séquence dans un test permet d'éviter la répétition d'un code très similaire et de s'assurer que les cas ultérieurs sont testés même si les cas antérieurs échouent. Cela encourage également les tests systématiques et uniformes, car les mêmes tests sont appliqués à chaque échantillon de données.
Lorsqu'un test est piloté par les données, vous pouvez spécifier son étiquette de données avec le nom de la fonction de test, comme function:tag, sur la ligne de commande du test pour exécuter le test sur un seul cas de test spécifique, plutôt que sur tous les cas de test de la fonction. Cela peut être utilisé pour une balise de données globale ou une balise locale, identifiant une ligne des données propres à la fonction ; vous pouvez même les combiner comme function:global:local.
Utiliser des outils de couverture
Utilisez un outil de couverture tel que Coco ou gcov pour vous aider à écrire des tests qui couvrent autant d'instructions, de branches et de conditions que possible dans la fonction ou la classe testée. Plus tôt cela est fait dans le cycle de développement d'une nouvelle fonctionnalité, plus il sera facile de détecter les régressions plus tard lorsque le code sera remanié.
Sélectionner les mécanismes appropriés pour exclure les tests
Il est important de sélectionner le mécanisme approprié pour exclure les tests inapplicables.
Utilisez QSKIP() pour gérer les cas où une fonction de test entière s'avère inapplicable dans l'environnement de test actuel. Lorsqu'une partie seulement d'une fonction de test doit être ignorée, une instruction conditionnelle peut être utilisée, éventuellement avec un appel à qDebug() pour signaler la raison de l'exclusion de la partie inapplicable.
Lorsqu'il existe des défaillances de test connues qui devraient être corrigées, QEXPECT_FAIL est recommandé, car il permet d'exécuter le reste du test, lorsque c'est possible. Cela permet également de vérifier que le problème existe toujours et d'informer le responsable du code s'il le corrige involontairement, un avantage qui est obtenu même en utilisant l'indicateur Abort.
Les fonctions de test ou les lignes de données d'un test piloté par les données peuvent être limitées à des plates-formes particulières, ou à des fonctionnalités particulières activées à l'aide de #if. Cependant, il faut se méfier des limitations moc lorsque l'on utilise #if pour sauter des fonctions de test. Le préprocesseur moc n'a pas accès à toutes les macros builtin du compilateur qui sont souvent utilisées pour la détection des caractéristiques du compilateur. Par conséquent, moc peut obtenir un résultat différent pour une condition du préprocesseur de celui vu par le reste de votre code. Cela peut avoir pour conséquence que moc génère des méta-données pour un slot de test que le compilateur réel ignore, ou qu'il omette les méta-données pour un slot de test qui est effectivement compilé dans la classe. Dans le premier cas, le test tentera d'exécuter un slot qui n'est pas implémenté. Dans le second cas, le test n'essaiera pas d'exécuter un slot de test alors qu'il devrait le faire.
Si un programme de test entier est inapplicable pour une plateforme spécifique ou si une fonctionnalité particulière n'est pas activée, la meilleure approche est d'utiliser la configuration de construction du répertoire parent pour éviter de construire le test. Par exemple, si le test tests/auto/gui/someclass n'est pas valide pour macOS, incluez son inclusion en tant que sous-répertoire dans tests/auto/gui/CMakeLists.txt dans une vérification de plate-forme :
if(NOT APPLE)
add_subdirectory(someclass)
endifou, si vous utilisez qmake, ajoutez la ligne suivante à tests/auto/gui.pro:
mac*: SUBDIRS -= someclass
Voir aussi Sauter des tests avec QSKIP.
Éviter Q_ASSERT
La macro Q_ASSERT provoque l'abandon d'un programme chaque fois que la condition affirmée est false, mais seulement si le logiciel a été construit en mode de débogage. Dans les versions release et debug-and-release, Q_ASSERT ne fait rien.
Q_ASSERT doit être évité parce qu'il fait en sorte que les tests se comportent différemment selon qu'une version de débogage est testée ou non, et parce qu'il provoque l'abandon immédiat d'un test, en sautant toutes les fonctions de test restantes et en renvoyant des résultats de test incomplets ou malformés.
Il ne tient pas compte non plus des opérations de démontage ou de rangement qui devaient avoir lieu à la fin du test, et peut donc laisser l'espace de travail dans un état désordonné, ce qui peut entraîner des complications pour les tests ultérieurs.
Au lieu de Q_ASSERT, il convient d'utiliser les variantes de la macro QCOMPARE() ou QVERIFY(). Elles entraînent l'échec et la fin du test en cours, mais permettent l'exécution des fonctions de test restantes et la fin normale de l'ensemble du programme de test. QVERIFY2 La macro () permet même d'enregistrer un message d'erreur descriptif dans le journal des tests.
Écrire des tests fiables
Les sections suivantes fournissent des lignes directrices pour l'écriture de tests fiables :
- Éviter les effets secondaires dans les étapes de vérification
- Éviter les délais fixes
- Attention au comportement dépendant du temps
- Éviter la capture et la comparaison de bitmaps
Éviter les effets secondaires dans les étapes de vérification
Lorsque vous effectuez des étapes de vérification dans un autotest en utilisant QCOMPARE(), QVERIFY(), et ainsi de suite, les effets de bord doivent être évités. Les effets de bord dans les étapes de vérification peuvent rendre un test difficile à comprendre. De plus, ils peuvent facilement casser un test d'une manière difficile à diagnostiquer lorsque le test est modifié pour utiliser QTRY_VERIFY(), QTRY_COMPARE() ou QBENCHMARK(). Celles-ci peuvent exécuter l'expression passée plusieurs fois, répétant ainsi les effets de bord.
Lorsque les effets secondaires sont inévitables, il faut s'assurer que l'état antérieur est rétabli à la fin de la fonction de test, même si le test échoue. Cela nécessite généralement l'utilisation d'une classe RAII (resource acquisition is initialization) qui restaure l'état lorsque la fonction revient, ou d'une méthode cleanup(). Ne vous contentez pas de placer le code de restauration à la fin du test. Si une partie du test échoue, ce code sera ignoré et l'état antérieur ne sera pas restauré.
Éviter les délais fixes
Évitez d'utiliser des délais d'attente codés en dur, tels que QTest::qWait() pour attendre que certaines conditions deviennent vraies. Pensez à utiliser la classe QSignalSpy, les macros QTRY_VERIFY() ou QTRY_COMPARE(), ou la classe QSignalSpy en conjonction avec les variantes de la macro QTRY_.
La fonction qWait() peut être utilisée pour fixer un délai d'une durée déterminée entre l'exécution d'une action et l'attente de la réalisation d'un comportement asynchrone déclenché par cette action. Par exemple, changer l'état d'un widget et attendre que le widget soit repeint. Cependant, de tels délais provoquent souvent des échecs lorsqu'un test écrit sur une station de travail est exécuté sur un appareil, où le comportement attendu peut prendre plus de temps. Augmenter le délai fixe à une valeur plusieurs fois supérieure à celle nécessaire sur la plate-forme de test la plus lente n'est pas une bonne solution, car cela ralentit l'exécution du test sur toutes les plates-formes, en particulier pour les tests pilotés par des tables.
Si le code testé émet des signaux Qt Test à la fin du comportement asynchrone, une meilleure approche consiste à utiliser la classe QSignalSpy pour notifier à la fonction de test que l'étape de vérification peut maintenant être exécutée.
S'il n'y a pas de signaux Qt, utilisez les macros QTRY_COMPARE() et QTRY_VERIFY(), qui testent périodiquement une condition spécifiée jusqu'à ce qu'elle devienne vraie ou qu'un certain délai maximum soit atteint. Ces macros empêchent le test de durer plus longtemps que nécessaire, tout en évitant les ruptures lorsque les tests sont écrits sur des stations de travail et exécutés ultérieurement sur des plates-formes embarquées.
S'il n'existe pas de signaux Qt Test et que vous écrivez le test dans le cadre du développement d'une nouvelle API, demandez-vous si l'API ne pourrait pas bénéficier de l'ajout d'un signal signalant l'achèvement du comportement asynchrone.
Attention au comportement dépendant du temps
Certaines stratégies de test sont vulnérables au comportement temporisé de certaines classes, ce qui peut conduire à des tests qui n'échouent que sur certaines plates-formes ou qui ne renvoient pas des résultats cohérents.
Les widgets de saisie de texte en sont un exemple : ils ont souvent un curseur clignotant qui peut faire réussir ou échouer les comparaisons de bitmaps capturés en fonction de l'état du curseur au moment de la capture du bitmap. Cet état peut à son tour dépendre de la vitesse de la machine qui exécute le test.
Lorsque l'on teste des classes qui changent d'état en fonction d'événements temporisés, il faut prendre en compte le comportement temporisé lors des étapes de vérification. En raison de la diversité des comportements dépendant de la temporisation, il n'existe pas de solution générique unique à ce problème de test.
Pour les widgets de saisie de texte, les solutions potentielles comprennent la désactivation du clignotement du curseur (si l'API fournit cette fonctionnalité), l'attente que le curseur soit dans un état connu avant de capturer une image bitmap (par exemple, en souscrivant à un signal approprié si l'API en fournit un), ou l'exclusion de la zone contenant le curseur de la comparaison d'images bitmap.
Éviter la capture et la comparaison d'images bitmap
S'il est parfois nécessaire de vérifier les résultats des tests en capturant et en comparant des images bitmap, cette méthode peut s'avérer assez fragile et nécessiter beaucoup de travail.
Par exemple, un widget particulier peut avoir une apparence différente sur différentes plates-formes ou avec différents styles de widget, de sorte que les bitmaps de référence peuvent avoir besoin d'être créés plusieurs fois et maintenus à l'avenir au fur et à mesure de l'évolution de l'ensemble des plates-formes prises en charge par Qt. Apporter des modifications qui affectent l'image bitmap signifie donc qu'il faut recréer les images bitmap attendues sur chaque plate-forme prise en charge, ce qui nécessite un accès à chaque plate-forme.
Les comparaisons de bitmaps peuvent également être influencées par des facteurs tels que la résolution de l'écran de la machine de test, la profondeur de bits, le thème actif, la palette de couleurs, le style des widgets, la localisation active (symboles monétaires, direction du texte, etc.), la taille de la police, les effets de transparence et le choix du gestionnaire de fenêtres.
Dans la mesure du possible, utilisez des moyens programmatiques, tels que la vérification des propriétés des objets et des variables, au lieu de capturer et de comparer des images bitmap.
Améliorer les résultats des tests
Les sections suivantes fournissent des lignes directrices pour produire des résultats de test lisibles et utiles :
- Tester les avertissements
- Éviter d'imprimer des messages de débogage à partir des tests automatiques
- Écrire un code de diagnostic bien structuré
Tester les avertissements
Tout comme lors de la construction de votre logiciel, si les résultats des tests sont encombrés d'avertissements, il vous sera plus difficile de remarquer un avertissement qui est réellement un indice de l'apparition d'un bogue. Il est donc prudent de vérifier régulièrement vos journaux de test pour y trouver des avertissements et d'autres sorties inutiles, et d'en rechercher les causes. Lorsqu'ils sont le signe d'un bogue, vous pouvez faire en sorte que les avertissements déclenchent l'échec du test.
Lorsque le code testé doit produire des messages, tels que des avertissements concernant une utilisation erronée, il est également important de tester qu'il les produit effectivement lorsqu'il est utilisé. Vous pouvez tester les messages attendus du code testé, produits par qWarning(), qDebug(), qInfo() et leurs amis, en utilisant QTest::ignoreMessage(). Cela permettra de vérifier que le message est produit et de le filtrer à partir de la sortie de l'exécution du test. Si le message n'est pas produit, le test échoue.
Si un message attendu n'est produit que lorsque Qt est construit en mode débogage, utilisez QLibraryInfo::isDebugBuild() pour déterminer si les bibliothèques Qt ont été construites en mode débogage. L'utilisation de #ifdef QT_DEBUG n'est pas suffisante, car elle vous dira seulement si le test a été construit en mode débogage, et cela ne garantit pas que les bibliothèques Qt ont également été construites en mode débogage.
Vos tests peuvent (depuis Qt 6.3) vérifier qu'ils ne déclenchent pas d'appels à qWarning() en appelant QTest::failOnWarning(). Cet appel prend en compte le message d'avertissement à tester ou un QRegularExpression à comparer aux avertissements ; si un avertissement correspondant est produit, il sera signalé et entraînera l'échec du test. Par exemple, un test qui ne devrait produire aucun message d'avertissement peut être confronté à QTest::failOnWarning(QRegularExpression(u".*"_s)), qui correspondra à n'importe quel message d'avertissement.
Vous pouvez également définir la variable d'environnement QT_FATAL_WARNINGS pour que les avertissements soient traités comme des erreurs fatales. Voir qWarning() pour plus de détails ; ceci n'est pas spécifique aux autotests. Si les avertissements seraient autrement perdus dans les vastes journaux de test, l'exécution occasionnelle avec cette variable d'environnement peut vous aider à trouver et à éliminer ceux qui surviennent.
Éviter d'imprimer des messages de débogage à partir des autotests
Les autotests ne devraient pas produire de messages d'avertissement ou de débogage non gérés. Cela permettra au CI Gate de traiter les nouveaux messages d'avertissement ou de débogage comme des échecs de test.
L'ajout de messages de débogage pendant le développement est acceptable, mais ils doivent être désactivés ou supprimés avant qu'un test ne soit validé.
Écrire un code de diagnostic bien structuré
Toute sortie de diagnostic qui serait utile en cas d'échec d'un test devrait faire partie de la sortie normale du test plutôt que d'être commentée, désactivée par des directives de préprocesseur ou activée uniquement dans les versions de débogage. Si un test échoue pendant l'intégration continue, le fait d'avoir toutes les sorties de diagnostic pertinentes dans les journaux de l'intégration continue peut vous faire gagner beaucoup de temps par rapport à l'activation du code de diagnostic et à un nouveau test. En particulier, si l'échec s'est produit sur une plateforme que vous n'avez pas sur votre bureau.
Les messages de diagnostic dans les tests doivent utiliser les mécanismes de sortie de Qt, tels que qDebug() et qWarning(), plutôt que les mécanismes de sortie stdio.h ou iostream.h. Ces derniers contournent la gestion des messages de Qt et empêchent l'option de ligne de commande -silent de supprimer les messages de diagnostic. Cela pourrait avoir pour conséquence que d'importants messages d'échec soient cachés dans un grand volume de sortie de débogage.
Écrire un code testable
Les sections suivantes fournissent des lignes directrices pour l'écriture d'un code facile à tester :
Casser les dépendances
L'idée des tests unitaires est d'utiliser chaque classe de manière isolée. Étant donné que de nombreuses classes instancient d'autres classes, il n'est pas possible d'instancier une classe séparément. Par conséquent, vous devez utiliser une technique appelée injection de dépendances qui sépare la création d'objets de leur utilisation. Une fabrique est responsable de la construction des arbres d'objets. D'autres objets manipulent ces objets par le biais d'interfaces abstraites.
Cette technique fonctionne bien pour les applications axées sur les données. Pour les applications GUI, cette approche peut s'avérer difficile car les objets sont fréquemment créés et détruits. Pour vérifier le comportement correct des classes qui dépendent d'interfaces abstraites, il est possible d'utiliser le mocking. Par exemple, voir le cadre Googletest Mocking (gMock).
Compiler toutes les classes dans des bibliothèques
Dans les projets de petite et moyenne taille, un script de compilation liste généralement tous les fichiers sources et compile ensuite l'exécutable en une seule fois. Cela signifie que les scripts de compilation des tests doivent à nouveau lister les fichiers sources nécessaires.
Il est plus facile de ne lister les fichiers sources et les en-têtes qu'une seule fois dans un script de construction d'une bibliothèque statique. Ensuite, la fonction main() sera liée à la bibliothèque statique pour construire l'exécutable et les tests seront liés aux bibliothèques statiques.
Pour les projets dans lesquels les mêmes fichiers sources sont utilisés dans la construction de plusieurs programmes, il peut être plus approprié de construire les classes partagées dans une bibliothèque liée dynamiquement (ou objet partagé) que chaque programme, y compris les programmes de test, peut charger au moment de l'exécution. Là encore, le fait d'avoir le code compilé dans une bibliothèque permet d'éviter les doublons dans la description des composants à combiner pour créer les différents programmes.
Configuration des machines de test
Les sections suivantes traitent des problèmes courants liés à la configuration des machines de test :
Tous ces problèmes peuvent être résolus par une utilisation judicieuse de la virtualisation.
Économiseurs d'écran
Les économiseurs d'écran peuvent interférer avec certains tests pour les classes d'interface graphique, entraînant des résultats de test peu fiables. Les économiseurs d'écran doivent être désactivés pour garantir la cohérence et la fiabilité des résultats des tests.
Dialogues du système
Les dialogues affichés de manière inattendue par le système d'exploitation ou d'autres applications en cours d'exécution peuvent voler le focus d'entrée des widgets impliqués dans un autotest, provoquant des échecs non reproductibles.
Parmi les exemples de problèmes typiques, on peut citer les boîtes de dialogue de notification de mise à jour en ligne sur macOS, les fausses alertes des scanners de virus, les tâches planifiées telles que les mises à jour des signatures de virus, les mises à jour logicielles envoyées aux postes de travail et les programmes de chat qui font apparaître des fenêtres au-dessus de la pile.
Utilisation de l'écran
Certains tests utilisent l'écran, la souris et le clavier de la machine de test et peuvent donc échouer si la machine est utilisée pour autre chose en même temps ou si plusieurs tests sont exécutés en parallèle.
Le système CI utilise des machines de test dédiées pour éviter ce problème, mais si vous ne disposez pas d'une machine de test dédiée, vous pouvez résoudre ce problème en exécutant les tests sur un deuxième écran.
Sous Unix, il est également possible d'exécuter les tests sur un serveur X imbriqué ou virtuel, tel que Xephyr. Par exemple, pour exécuter l'ensemble des tests sur Xephyr, exécutez les commandes suivantes :
Xephyr :1 -ac -screen 1920x1200 >/dev/null 2>&1 & sleep 5 DISPLAY=:1 icewm >/dev/null 2>&1 & cd tests/auto make DISPLAY=:1 make -k -j1 check
Les utilisateurs de pilotes binaires NVIDIA doivent noter que Xephyr peut ne pas être en mesure de fournir des extensions GLX. Forcer Mesa libGL peut aider :
export LD_PRELOAD=/usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1
Cependant, lorsque les tests sont exécutés sur Xephyr et le vrai serveur X avec différentes versions de libGL, le cache disque QML peut faire planter les tests. Pour éviter cela, utilisez QML_DISABLE_DISK_CACHE=1.
Vous pouvez également utiliser le plugin offscreen :
TESTARGS="-platform offscreen" make check -k -j1
Gestionnaires de fenêtres
Sous Unix, au moins deux tests automatiques (tst_examples et tst_gestures) nécessitent l'exécution d'un gestionnaire de fenêtres. Par conséquent, si vous exécutez ces tests sous un serveur X imbriqué, vous devez également exécuter un gestionnaire de fenêtres dans ce serveur X. Votre gestionnaire de fenêtres doit être configuré de manière à ce qu'il soit positionné à l'intérieur de l'écran.
Votre gestionnaire de fenêtres doit être configuré pour positionner automatiquement toutes les fenêtres sur l'écran. Certains gestionnaires de fenêtres, tels que Tab Window Manager (twm), disposent d'un mode de positionnement manuel des nouvelles fenêtres, ce qui empêche l'exécution de la suite de tests sans interaction de l'utilisateur.
Remarque : Tab Window Manager n'est pas adapté à l'exécution de la suite complète d'autotests Qt, car l'autotest tst_gestures lui fait oublier sa configuration et revenir à un positionnement manuel des fenêtres.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.