Intégration des applications Qt6 et Unity dans l'automatisation des tests
Dans le monde des interfaces homme-machine (HMI), l'intégration de technologies diverses pour offrir des expériences utilisateur fluides pose des défis uniques. Examinons la conception et les tests d'applications multi-technologies comportant des fonctions critiques et non critiques pour la sécurité, distinctes. En exploitant des outils spécialisés tels que Squish pour Qt et AltTester SDK pour Unity, nous présentons une approche globale pour unifier l'automatisation des tests, garantissant un développement efficace et une assurance qualité robuste. Découvrez comment ces méthodologies peuvent rationaliser vos projets HMI, réduire les coûts indirects et améliorer la qualité globale des logiciels.
Introduction au HMI automobile et à la séparation des interfaces
La conception de l'interface homme-machine (HMI) implique la création d'interfaces utilisateur permettant aux utilisateurs d'interagir efficacement avec les machines. Dans le dans le contexte de l'industrie automobile, les HMI sont des solutions particulièrement complexes car les utilisateurs interagissent avec une voiture à plusieurs niveaux : la conduite, l'utilisation des services de divertissement, le réglage du chauffage, et bien plus encore.
Chaque niveau de service revêt une importance variable ; par exemple, ne pas répondre à une commande vocale pour baisser une vitre est relativement insignifiant, mais ne pas afficher un avertissement ABS peut être dangereux. C'est pourquoi les normes de l'industrie automobile distinguent différents types d'applications et de services. Les applications liées à la sécurité sont séparées des applications non liées à la sécurité, et les signaux des fonctions critiques, comme les freins, sont transmis par un câblage différent de celui des fonctions non critiques, comme la navigation.
Dans de tels cas, l'équipe d'ingénierie doit développer des applications distinctes pour l'HMI et parfois choisir des technologies différentes pour atteindre cet objectif. Finalement, les deux applications sont affichées l'une sur l'autre et offrent une expérience utilisateur complète.
Du point de vue du développement, cette méthode est considérée comme efficace – le système n'a besoin que de lancer et d'exécuter deux applications. Les designers et développeurs d'interfaces utilisateur assurent une intégration esthétique de ces applications. En outre, cette approche présente des avantages supplémentaires : les applications utilisant des technologies diverses peuvent être développées par des équipes indépendantes, évitant ainsi toute interférence opérationnelle entre elles.
Défis liés aux tests d'applications HMI multi-technologies
Examinons à présent plus en détail le processus de test de telles applications. Chacune sera gérée par des équipes de test distinctes chargées de développer une automatisation indépendante pour ces applications. En outre, les résultats des tests et l'assurance qualité seront conduits séparément pour chacune. Le terme « séparé » est ici crucial ; s'il facilite la phase de développement, il s'avère moins bénéfique lors des tests. Une telle séparation introduit des efforts et des surcoûts supplémentaires et laisse en suspens la question du comportement global du système.
Intégration des applications Qt6 et Unity dans l'automatisation des tests
Nous avons une application basée sur Qt6 qui affiche du contenu statique, comme des icônes, des messages d'avertissement ou des menus. Sur la seconde couche, nous avons une application basée sur Unity. Elle affiche des animations de vitesse et de RPM, des cartes animées, et plus encore, en utilisant une approche de scène 3D.
La tâche consiste à créer une automatisation des tests pour une telle configuration. Les applications sont livrées dans un simulateur virtuel – il peut s'agir d'une image QEMU ou Docker. Une exigence incontournable est de combiner l'automatisation des tests dans un seul framework de test et de créer des cas de test pour tester les deux applications en une seule fois.

Choisir les bons outils : Squish pour Qt et AltTester SDK pour Unity
En ce qui concerne Qt, la seule approche raisonnable consiste à utiliser les outils du portefeuille Qt pour tester l'application. Ils sont conçus pour prendre en charge pleinement leur propre technologie. Le framework de test officiel conçu pour Qt est Squish. Cette solution est notre premier (et unique) choix, car elle offre un support complet et une expérience d'automatisation des tests transparente et prête à l'emploi.
Le choix du framework de test pour l'application Unity comporte certaines contraintes à respecter :
- la possibilité de se connecter avec Squish,
- prix raisonnable,
- utilisation en mode headless (à des fins de CI).
L'un des outils évalués préliminairement était AltTester SDK – un framework open source maintenu par la société Alttom. Alttom propose une version commerciale d'AltTester avec un support complet et des possibilités améliorées.
Pour nos besoins, le SDK AltTester a suffi pour démarrer l'implémentation initiale et a couvert l'ensemble de nos exigences.
Concevoir une architecture unifiée de framework de test
Après avoir évalué les outils, nous avons décidé que Squish serait notre base pour toutes les activités de test, telles que l'exécution de tests ou la préparation de rapports.
En effet, l'AltTester SDK n'est pas un framework de test entièrement fonctionnel, mais plutôt un pilote, permettant de se connecter à une application Unity instrumentée et d'inspecter ses éléments. Il ne dispose d'aucune option de reporting (à l'exception de la méthode de capture d'écran) et, pour exécuter les tests écrits pour lui, il faudrait lancer des scripts Python, C# ou JAVA ou utiliser un framework de test, qui fournira toutes les fonctionnalités liées aux tests (comme l'approche BDD ou le reporting).
Ci-dessous, vous pouvez consulter l'architecture finale que nous avons décidé de mettre en œuvre.
L'application Unity est instrumentée lors du processus de build avec le plugin AltTester SDK Unity, le runner de tests Squish, des wrappers Python et des helpers écrits pour fournir les fonctionnalités souhaitées, ainsi que des fichiers contenant les cartes d'objets pour les deux applications.

Le runner exécute les tests en se connectant aux applications Qt (connexion native) et Unity (via le SDK AltDriver). Il exécute les étapes rédigées selon l'approche BDD, collecte les logs, les captures d'écran et autres artefacts de test, puis regroupe le tout dans un rapport de test.
Rendre les applications HMI testables avec Squish et AltTester SDK
Le framework de test doit se connecter aux applications testées pour faire fonctionner les choses.
L'instrumentation Squish peut être réalisée de deux manières :
- s'accrocher à l'application lors de son démarrage,
- intégrer le hook Squish dans l'application lors de sa compilation.
Nous avons décidé d'opter pour la première option, car la configuration de l'environnement de test nous le permettait.
Le SDK AltTester doit être ajouté lors de la phase de build de l'application Unity. Il est impossible d'instrumenter une application déjà compilée, ce qui introduit certaines difficultés. Plus important encore, si nous voulons utiliser le SDK AltTester, nous devons avoir accès au processus de build de l'application Unity et le modifier pour fournir l'instrumentation.
La façon dont l'application Unity est instrumentée est assez simple : l'utilisateur doit compiler le plugin AltTester SDK, ajouter quelques dépendances au projet Unity et importer le plugin dans celui-ci (documentation sur l'importation du package AltTester dans Unity Editor).
Bien entendu, d'autres ajustements et modifications peuvent être nécessaires, selon les spécifications du projet. Nous avons dû modifier le script de build du projet Unity pour que tout fonctionne. Voici un exemple d'instrumentation en ligne de commande :
# Étape 1 : Configurer le projet Unity avec les dépendances. python3 update_for_altester.py # Étape 2 : Importer le plugin Unity AltTester. ./Unity -quit -batchmode -nographics -disableaudio -importPackage AltTester-1.8.2.unitypackage -projectPath . # Étape 3 : Compiler le projet à l'aide d'une méthode de compilation personnalisée. ./Unity -quit -batchmode -nographics -disableaudio -projectPath . -executeMethod SpyroBuilder.BuildAltTester
Implémentation du framework de test : cartes d'objets et plus encore
À ce stade, nous avions les applications Squish et Unity connectées à notre framework de test. Les tests pouvaient inspecter les objets dans les deux applications, vérifier leurs propriétés, interagir avec eux et exécuter toutes les activités de test que nous avions conçues.
Cartes d'objets
Nous avons créé des cartes d'objets pour les deux applications afin d'accéder rapidement et simplement aux objets.
Une carte d'objets Squish peut être créée automatiquement à l'aide de Squish IDE et d'outils d'inspection. Les objets sont des noms symboliques, et leurs valeurs sont définies par une liste de paramètres, comme « title », « type », etc. Voici un exemple de carte d'objets Squish :
# Vue principale du lecteur multimédia media_player_screen_main_view = { "title": "MediaPlayer", "type": "QQuickWindowQmlImpl", "visible": True } # Objets de la liste de lecture du lecteur multimédia media_player_playlist_view = { "container": media_player_screen_main_view, "type": "ListsScreen", "visible": True } media_player_playlist_text = { "container": media_player_playlist_view, "text": "Liste de lecture", "type": "Text", "visible": True }
Une fois l'objet défini, Squish peut l'atteindre, vérifier ses propriétés ou interagir avec lui. Voici un exemple de méthode wrapper pour trouver des objets dans Squish :
def find_object(obj, timeout=1000, visible_object=True): """Recherche et renvoie un objet. Ne journalise pas. Args: object_name (str ou object): Nom de l'objet à rechercher timeout (int): Délai de recherche en ms. Valeur par défaut : 1000. visible_object (bool): L'objet est-il visible ? Définit la fonction Squish à utiliser. Returns: obj: Objet trouvé, ou None s'il n'est pas trouvé. """ try: if isinstance(obj, str): if visible_object: obj = squish.waitForObject(getattr(names, obj), timeout) else: obj = squish.findObject(getattr(names, obj)) except LookupError as ex: return None except Exception as ex: raise Exception(ex) return obj
Et à l'intérieur de l'IDE Squish…

Les cartes d'objets Unity avec le SDK AltTester sont un peu plus délicates. Elles peuvent être créées à l'aide de Unity Editor (la méthode la plus simple) ou avec le pilote du SDK AltTester et une inspection manuelle depuis la ligne de commande.
Le SDK AltTester permet l'identification d'objets par des méthodes telles que le nom, le chemin, le texte, l'ID et autres. Il peut être utilisé en fonction de la configuration de la scène ou de l'arborescence des objets et offre la flexibilité nécessaire pour implémenter des fonctions de recherche d'objets. Voici un exemple de notre carte d'objets pour l'application Unity.
charging_toggle = {"by_selector": "NAME", "search_value": "Charging_Toggle"} navigation_toggle = {"by_selector": "NAME", "search_value": "Navigation_Toggle"} vehicle_toggle = {"by_selector": "NAME", "search_value": "Vehicle_Toggle"} engine_economy_button = {"by_selector": "NAME", "search_value": "CarToggleForGroup (1)"} engine_economy_label = {"by_selector": "PATH", "search_value": "//CarToggleForGroup (1)[1]"} engine_balanced_button = {"by_selector": "NAME", "search_value": "CarToggleForGroup (2)"} engine_balanced_label = {"by_selector": "PATH", "search_value": "//CarToggleForGroup (2)[1]"} engine_performance_button = {"by_selector": "NAME", "search_value": "CarToggleForGroup (3)"} engine_performance_label = {"by_selector": "PATH", "search_value": "//CarToggleForGroup (3)[1]"}
La fonction permettant d'obtenir des objets depuis la scène peut ressembler à ceci :
def get_object(object_name, is_enabled=True, timeout=0): """Finds and returns an object. Does not log. Args: object_name (str): Name of the object to be found. is_enabled (bool): is object active (true by default) Raises: Exception: When exceptions other than 'object not found' are encountered Returns: obj: Found object, or None if not found. """ try: obj_data = getattr(names, object_name) if timeout > 0: return driver.wait_for_object( getattr(alttester.By, obj_data["by_selector"]), obj_data["search_value"], enabled=is_enabled, timeout=timeout, interval=0.2, ) else: return driver.find_object( getattr(alttester.By, obj_data["by_selector"]), obj_data["search_value"], enabled=is_enabled, ) except (alttester.NotFoundException, alttester.WaitTimeOutException) as ex: return None except Exception as ex: logger.info(f"Exception while looking for object: |{object_name}|") raise Exception(ex)
Dans la ligne de commande Python, la recherche d'objets se présente comme suit :

Dans l'application Unity, il s'agit d'un exemple d'objet :

Comme déjà mentionné, le SDK AltTester permet de trouver des objets à l'aide de plusieurs méthodes. Dans cet exemple, la méthode By.NAME a été utilisée, mais un utilisateur peut choisir entre PATH, TEXT, ID et d'autres (documentation sur la recherche d'objets).
Lorsqu'un objet est trouvé, Squish et AltTester SDK permettent tous deux à l'utilisateur d'inspecter ses propriétés, d'obtenir le texte de l'objet, de cliquer dessus ou d'effectuer toute autre action nécessaire à la création d'une étape de test.
Capacités API de Squish et du SDK AltTester
Le SDK AltTester expose une API pour trouver des objets, interagir avec eux et inspecter leurs propriétés. Certaines fonctionnalités utiles permettent aux utilisateurs d'explorer plus en profondeur l'application Unity, comme l'appel de méthodes de composants Unity ou l'interaction avec les propriétés des composants. Les fonctions liées aux scènes sont également en place : elles peuvent être utilisées pour charger ou décharger la scène souhaitée, ou pour vérifier que la scène actuelle est correcte. Une autre méthode consiste à capturer une capture d'écran. La fonction prend une capture d'écran et l'enregistre sous forme de fichier PNG, qui peut ensuite être joint aux rapports de test.
L'API Squish, à l'exception des méthodes liées aux tests, fournit les fonctionnalités nécessaires pour organiser le déroulement des tests. Par exemple, l'utilisateur peut reprendre et encapsuler la méthode test.fail() et y ajouter d'autres éléments requis par la configuration de test. Dans notre cas, nous avons encapsulé test.fail() afin d'apporter une fonctionnalité supplémentaire à l'étape de test en échec lors du test de l'application Unity, et nous avons ajouté l'étape de capture d'écran du SDK AltTester :
def screenshot(): """Prend une capture d'écran Args: aucun Retourne: aucun """ dt = datetime.now() timestamp = dt.strftime("%Y%m%d_%H%M%S") path = Path(f'{os.getcwd()}/screenshots') if not os.path.exists(path): os.makedirs(path) scr_path = Path(f'{path}/screenshot_{timestamp}.png') try: driver.get_png_screenshot(path=scr_path) test.attachFile(str(scr_path), "Alttester screenshot") except: test.xfail("Un problème est survenu lors de la capture d'écran") def test_fail(fail_message): screenshot() test.fail(fail_message)
Gestion des interactions
Les deux outils offrent des interactions.
Dans Squish, il existe plusieurs méthodes, comme tap ou click, ou même la classe Gesture Builder, qui permet de créer des gestes simples et complexes.
Le SDK AltTester adopte une approche similaire, allant de simples méthodes de pression ou de déplacement à des interactions multipoints complexes. Il peut créer des interactions tactiles (BeginTouch(), MoveTouch(), EndTouch()). Ainsi, dans les deux cas, les utilisateurs peuvent simuler facilement et de manière flexible des interactions et des gestes.
L'impact de l'automatisation intégrée des tests sur la qualité logicielle
L'utilisation conjointe d'AltTester SDK et de Squish nous a permis de créer des scénarios de test capables de tester deux applications développées avec des technologies différentes. Les scénarios pouvaient changer de contexte de manière fluide et exécuter les étapes de test. Les rapports de test fournissent toutes les informations nécessaires en un seul endroit, et il n'est pas nécessaire de créer des pipelines distincts dans le CI pour exécuter l'ensemble de l'automatisation.
Recherchez-vous des spécialistes HMI ?
Découvrez comment nous pouvons accompagner votre prochain produit – consultez notre offre HMI, et n'hésitez pas à nous contacter en cas de questions.
FAQ
L'intégration de Qt6 et Unity permet aux développeurs de combiner des interfaces utilisateur créées dans Qt avec des environnements 3D créés dans Unity. Cela permet des applications plus avancées, notamment dans les scénarios de simulation, de HMI ou de visualisation.
L'utilisation de Qt6 et Unity dans l'automatisation des tests permet aux équipes de valider à la fois la logique de l'interface utilisateur et les interactions 3D au sein d'un même workflow. Cela permet de garantir que la communication entre les composants fonctionne correctement sur l'ensemble de l'application.
Les applications Qt6 et Unity communiquent généralement via des interfaces définies telles que des sockets, des API ou des mécanismes de messagerie. Cela leur permet d'échanger des données et de synchroniser leur comportement en cours d'exécution et lors des tests.
Les principaux défis incluent la synchronisation de la communication, la gestion de différents environnements d'exécution et la garantie d'un comportement cohérent lors des tests automatisés. Une architecture appropriée et des interfaces claires contribuent à réduire ces risques.
Cette approche est particulièrement utile dans les projets impliquant des simulations, des systèmes HMI ou des applications où un environnement 3D doit être contrôlé ou étendu par une interface basée sur Qt.
arrow_circle_rightContactez-nous
Besoin d'assistance pour une application basée sur Qt ou Unity ? Notre équipe est prête à vous aider
arrow_circle_right Autres articles