Introduction à System.Windows.Automation

L'automation consiste à automatiser les interactions avec une application au niveau UI. En d'autres mots, il s'agit de "scripter" une application en interagissant avec les états et valeurs de ses contrôles. Les intérêts de l'automation sont multiples, mais les deux raisons principales poussant à son utilisation sont en général les suivantes:

  • Effectuer des tests automatisés 
  • Exécuter une suite d'actions sur une application lorsque des APIs dédiées ne sont pas disponibles, ou trop difficilement accessibles

L'API d'automation recommandée aujourd'hui est disponible dans le namespace System.WindowsAutomation depuis la version 3.0 du framework .NET.

Préparation de l'application à automatiser

image

Dans le cadre de cet article, j'ai réalisé une application très simple prenant quelques entrées utilisateur, suivi d'un bouton de validation qui cochera ou non une case indiquant si les informations fournies sont valides. L'application testée est considérée comme le serveur d'automation, et l'application qui la contrôlera est le client. Préparer l'application WPF à l'automation est extrêmement simple, et s'effectue par le biais de la propriété attachée AutomationProperties.AutomationId sur les contrôles que l'on souhaite rendre disponible au serveur.

<Slider x:Name="sldAge" AutomationProperties.AutomationId="sldAge" …/>

Obtention des AutomationElements et des patterns
Le serveur utilisé pour tester l'application est une application console qui s’attache à l'exécutable client et obtient les contrôles identifiés par leurs AutomationIds. Notons que le serveur n'identifie pas les contrôles comme tels, mais plutôt comme des AutomationElements.

AutomationElement sldAge = aeForm.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIdProperty, "sldAge"));

Un AutomationElement est une partie d'UI avec lequel on peut interagir par le biais de motifs (patterns). Les AutomationElements ne sont d'ailleurs pas forcément liés à des contrôles WPF : il est tout à fait possible d'utiliser un même serveur pour interagir aussi bien avec une application WPF qu'avec une application Windows Forms tant que les les deux programmes mettent à disposition les mêmes AutomationIds associés aux mêmes patterns. L'abstraction des motifs est cruciale car elle permet à System.Windows.Automation d’être indépendant de la technologie. Par exemple, les sliders WPF et Windows Forms ont tous deux un même motif de type RangeValuePattern, les radios ont toujours des SelectionItemPattern, etc. (consultez le tableau des patterns pour connaître ces associations).

var vpTxtNom = (ValuePattern)txtNom.GetCurrentPattern(ValuePattern.Pattern);

Interagir avec les éléments
Une fois le pattern d'un AutomationElement acquis, il devient possible d'interagir avec le contrôle sous-jacent. Chaque pattern offre différentes méthodes d'interaction : RangeValuePattern permet de définir une valeur, InvokePattern permet de déclencher une action, SelectionItemPattern permet d'effectuer une sélection, et ainsi de suite. Ces patterns permettent également de lire les valeurs ou l’état d’un AutomationElement, ouvrant ainsi la voie aux scénarios de test.

vpTxtNom.SetValue("Jean Dupont");
rvSldAge.SetValue(55);

if (tpChkAcceptation.Current.ToggleState != ToggleState.Off) // test échoué!

Ce n'est pas une simulation d'input!
Il faut cependant noter un point important : l’Automation n’est pas une solution de « simulation d’utilisateur » et ne permet pas de simuler l’utilisation des périphériques comme le clavier, la souris ou le stylet. Prenons l’exemple d’un bouton et de son InvokePattern. Lors de l’appel à la méthode Invoke(), le bouton est utilisé sans pour autant simuler d’action physique de l’utilisateur : aucun un clic de souris, de pression de la touche Entrée n’est déclenché. Simuler une interaction par un périphérique nécessite un appel natif à la méthode SendInput (ou plus simplement via le wrapper SendKeys pour les applications Windows Forms). Vous pourrez d'ailleurs observer que dans le projet exemple, KeyDown n'est jamais appelé lorsque le client est commandé par le serveur.

J'espère que cet article et son projet exemple vous auront permis de démarrer l'automation en douceur, tout en vous sensibilisant aux avantages qu’apporte un bon support de cette API par vos applications. Bien que les concepts évoqués soient nouveaux pour beaucoup de développeurs, les possibilités offertes par cette API sont nombreuses et ne manqueront d’ailleurs pas de s'étoffer dans les versions à venir.

Liens :
 Bibliothèques d’automation d'interface utilisateur Microsoft : Un article plus détaillé sur les concepts d’automation, et un exemple avec une application Windows Forms.
 Mappage de modèle de contrôle pour les clients UI Automation : Tableau récapitulant quels patterns sont disponibles pour chaque contrôle commun.

WpfAutomationExample.zip