Partager via


Cet article a fait l'objet d'une traduction automatique.

Série de tests

Automation de test d'interface utilisateur Web avec le contrôle WebBrowser

James McCaffrey

Télécharger l'exemple de code

James McCaffreyDans l'article de mois-ci ce je vous montrerai une nouvelle façon de créer l'automation de test d'interface utilisateur pour les applications Web. La technique que je présente fournit une solution à un scénario de test très courant mais difficile : comment traiter les boîtes de message modale générés par une application Web.

Vous pouvez voir où je suis se transforme en, la meilleure consiste à examiner les captures d'écran dans les figures 1 et de 2 . L'image dans les de la figure 1 illustre une application Web simpliste mais représentative hébergée dans Internet Explorer. L'application accepte les entrées d'utilisateur dans une zone de texte et une fois que l'utilisateur clique sur le bouton Click Me, l'application identifie la couleur de l'élément d'entrée, puis affiche le résultat dans la deuxième zone de texte.

image: Example Web App Under Test

Figure 1 exemple d'application Web en cours de test,

Notez que lorsque vous cliquez sur le clic de bouton Notifier, la logique l'application vérifie pour voir si la zone d'entrée utilisateur est vide. Dans ce cas, il génère une boîte de dialogue modale avec un message d'erreur. Gérer une boîte de message est problématique en partie parce que la boîte de message n'est pas le navigateur ou le document du navigateur.

Maintenant examinons l'exemple de test s'exécutent dans les figure 2. Le faisceau de tests est une application Windows Forms. Incorporé dans les Windows Forms app est un contrôle WebBrowser qui permet les Windows Forms pour afficher et manipuler l'application Web factice à tester.

image: Example Test Run

La figure 2 exemple tests

Si vous examinez les messages dans le contrôle ListBox en bas de l'atelier de Windows Forms, vous verrez que l'atelier de test commence par charger l'application Web en cours de test dans le contrôle WebBrowser. Ensuite, l'atelier utilise un thread d'exécution séparé pour surveiller les — et les traiter, les messages générés par l'application Web. Le faisceau simule un clic d'utilisateur sur l'application Web Click Me button, qui à son tour crée une boîte de message modale d'erreur. Le thread d'observation détecte que la boîte de message et simule un utilisateur en cliquant sur Supprimer. L'atelier de test termine en simulant un utilisateur tapant “ roses ” dans la première zone d'entrée, cliquez sur le Click Me bouton, puis recherchez le scénario de test attendu de réponse de “ rouge ” dans la deuxième zone de texte.

Dans cet article, je décris brièvement l'application Web testée d'exemple. Je puis vous guident le code de l'atelier de test de Windows Forms afin que vous serez en mesure de modifier mon code pour répondre à vos scénarios de tests. J'ai conclut en décrivant les situations où cette technique est applicable et de techniques de remplacement peuvent être plus judicieux.

Cet article suppose que vous avez les compétences de développement de base Web et de compétences de codage intermédiaire Visual c#, mais même si vous êtes novice en c# vous devez pouvoir suivre sans niveau de difficulté. Je pense que vous trouverez la technique que je présente ici un complément utile à vos tests de logiciels personnels, kit d'outil de développement et de gestion.

L'application testée

Let’s, examinez le code de l'exemple d'application Web qui est la cible de mon automation de test. Par souci de simplicité, j'ai créé l'application en utilisant le bloc-notes. La fonctionnalité d'application est fournie par le code JavaScript côté client plutôt que par un traitement côté serveur. Comme je l'expliquerai plus tard, cette technique d'automation de test doit fonctionner avec les applications en fonction de la plupart des technologies Web (ASP.NET, Perl/CGI et ainsi de suite), mais la technique est idéale pour les applications qui utilisent JavaScript pour générer des boîtes de message. L'ensemble du code d'application Web est présenté dans les figure 3.

La figure 3 de l'application Web

    <html>
    <head>
    <title>Item Color Web Application</title>
    <script language="JavaScript">
      function processclick() {
        if (document.all['TextBox1'].value == "") {
          alert("You must enter an item into the first box!");
        }
        else {
          var txt = document.all['TextBox1'].value;
          if (txt == "roses")
            document.all["TextBox2"].value = "red";
          else if (txt == "sky")
            document.all["TextBox2"].value = "blue";
          else
            document.all["TextBox2"].value = "I don't know that item";
        }
      }
    
    </script>
    </head>
    <body bgcolor="#F5DEB3">
      <h3>Color Identifier Web Application</h3>
      <p>Enter an item: 
        <input type="text" id="TextBox1" /></p>
      <p><input type="button" value="Click Me" 
                id="Button1" 
                onclick="processclick()"/></p>
      <p>Item color is: 
        <input type="text" id="TextBox2" /></p>
    </body>
    </html>

J'ai enregistré mon application Web default.html dans un répertoire nommé ColorApp représenté dans le répertoire C:\inetpub\wwwroot sur mon ordinateur hôte de test. Pour diriger désactivez des problèmes de sécurité, la technique que je présente ici fonctionne mieux lorsque l'automation de test est exécuté directement sur l'ordinateur qui joue le rôle du serveur Web qui héberge l'application testée. Pour simplifier dans mon application de Web exemple et se superposent pas aux détails de l'automation de test, j'ai pris des raccourcis que vous ne voudriez pas voir la rubrique dans une application Web de production, telles que l'élimination des vérifications des erreurs.

Au cœur des fonctionnalités de l'application Web est contenu dans une fonction JavaScript appelée processclick. Cette fonction est appelée lorsqu'un utilisateur clique sur le contrôle de bouton de l'application avec l'ID Button1 et valeur d'étiquette “ Click Me. ” La fonction processclick vérifie tout d'abord si la valeur de l'élément d'entrée TextBox1 est vide. Dans ce cas, il génère une boîte de message d'erreur à l'aide de la fonction d'alerte de JavaScript. Si l'élément input de TextBox1 n'est pas vide, la fonction processclick utilise une instruction si-alors pour produire une valeur de l'élément de TextBox2. Notez que parce que la fonctionnalité de l'application Web est fournie par le code JavaScript côté client, l'application n'effectue pas de plusieurs aller-retour client-serveur et par conséquent, l'application Web est chargée qu'une seule fois par cycle de fonctionnalités.

L'atelier de test de Windows Forms

Maintenant let’s passez en revue le code de harnais de test illustré à la de la figure 2 afin que vous serez en mesure de modifier le code pour répondre à vos besoins. Le faisceau de tests est une application Windows Forms ;normalement, j'utiliserais Visual Studio pour créer le programme. Cependant, je vais vous montrer comment créer le faisceau à l'aide du bloc-notes et le compilateur c# de ligne de commande parce que la facilité d'utilisation et le code généré automatiquement dans Visual Studio masquer certains des concepts importants. Une fois que vous comprenez mon exemple de code, vous devez avoir sans problème à l'aide de Visual Studio plutôt que le bloc-notes.

Ouvrir le bloc-notes et de le commencer mon atelier en déclarant les espaces de noms utilisé :

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;

Vous devez les espaces de noms System, de formulaires et de dessin pour les fonctionnalités de Windows Forms de base. L'espace de noms InteropServices permet à l'atelier de test rechercher et de manipuler les boîtes de dialogue modale à l'aide du mécanisme P/Invoke. P/Invoke permet de créer des méthodes wrapper c# qui appellent des fonctions Win32 API natives. L'espace de noms de thread est utilisée pour faire tourner sur un thread séparé qui surveille l'apparence des zones de message.

Ensuite je déclare un espace de noms harnais et je commence le code de la classe d'application Windows Forms principal, qui hérite de la classe System.Windows.Forms.Form :

namespace TestHarness
{
  public class Form1 : Form
  {
    [DllImport("user32.dll", 
      EntryPoint="FindWindow",
      CharSet=CharSet.Auto)]
    static extern IntPtr FindWindow(
      string lpClassName,
      string lpWindowName);
.
.
.

Immédiatement à l'intérieur de la définition de Form1, je place un attribut de portée de la classe qui permet à l'atelier de test appeler la fonction FindWindow API externe, ce qui se trouve dans user32.dll. La fonction FindWindow API est mappée à une méthode c# également nommée FindWindow, qui accepte le nom interne d'un contrôle de fenêtre et retourne un handle IntPtr vers le contrôle. La méthode FindWindow va être utilisée par le faisceau de tests pour obtenir un handle pour la boîte de message généré par l'application Web en cours de test.

Ensuite, j'ajoute deux attributs plus à activer des fonctionnalités supplémentaires de Win32 API :

[DllImport("user32.dll", EntryPoint="FindWindowEx",
  CharSet=CharSet.Auto)]
static extern IntPtr FindWindowEx(IntPtr hwndParent,
  IntPtr hwndChildAfter, string lpszClass, 
  string lpszWindow);

[DllImport("user32.dll", EntryPoint="PostMessage",
  CharSet=CharSet.Auto)]
static extern bool PostMessage1(IntPtr hWnd, uint Msg,
  int wParam, int lParam);

La méthode c# FindWindowEx associée à la fonction FindWindowEx API va être utilisée pour obtenir un contrôle enfant du contrôle trouvé par FindWindow, à savoir le bouton OK dans la boîte de message. La méthode c# PostMessage1 associée à la fonction PostMessage API va servir à envoyer une souris en - up et de la souris - vers le bas du message : en d'autres termes, un clic, pour le bouton OK.

Puis je déclare exploitent les trois contrôles de portée de la classe qui font partie de the Windows Forms :

private WebBrowser wb = null;
private Button button1 = null;
private ListBox listBox1 = null;

Le contrôle WebBrowser constitue un wrapper de code managé autour du code natif qui contient les fonctionnalités du navigateur Internet Explorer Web. Le contrôle WebBrowser expose des méthodes et propriétés qui peuvent être utilisées pour examiner et manipuler une page Web hébergée dans le contrôle. Le contrôle Button qui sera utilisé pour lancer l'automatisation des tests et le contrôle ListBox est utilisé pour afficher les messages de journalisation harnais de test.

Ensuite, je commence le code pour le constructeur de Form1 :

public Form1() {
    // button1
    button1 = new Button();
    button1.Location = 
      new Point(20, 430);
    button1.Size = new Size(90, 23);
    button1.Text = "Load and Test";
    button1.Click += 
      new EventHandler(
      this.button1_Click);
  .
.
.

Ce code doit être relativement explicite. Il est tout à fait possible que vous n'avez jamais eu à écrire du code d'interface utilisateur de Windows Forms comme suit à partir de zéro avant, car Visual Studio effectue un très bon travail de génération de code boilerplate de l'interface utilisateur. Notez le modèle : instancier un contrôle, définissez les propriétés et puis raccorder des méthodes de gestionnaire d'événements. Vous verrez ce modèle de même avec le contrôle WebBrowser. Lorsque vous utilisez la technique d'automation de test que je présente dans cet article, il est utile de disposer d'un moyen d'afficher des messages de journalisation et un contrôle ListBox est efficace :

// listBox1
listBox1 = new ListBox();
listBox1.Location = new Point(10, 460);
listBox1.Size = new Size(460, 200);

Ensuite j'ai configuré le contrôle WebBrowser :

// wb
wb = new System.Windows.Forms.WebBrowser();
wb.Location = new Point(10,10);
wb.Size = new Size(460, 400);
wb.DocumentCompleted +=
  new WebBrowserDocumentCompletedEventHandler(ExerciseApp);

La clé chose à noter ici est que j'ai raccorder une méthode de gestionnaire d'événements pour l'événement DocumentCompleted afin que, après que l'application Web testée est entièrement chargée dans le contrôle WebBrowser, contrôle d'exécution sera transférée dans une méthode définie par le programme nommée ExerciseApp (que je n'ai pas encore codé). Ceci est important, car dans presque toutes les situations il aura un délai pendant le charge de l'application Web et toute tentative d'accéder à l'application Web dans le contrôle avant qu'il soit entièrement chargé lèvera une exception.

Vous avez peut-être deviné qu'une façon de gérer cela consiste à placer une instruction thread.Sleep dans l'atelier de test. Mais parce que l'atelier et le contrôle WebBrowser exécutent tous deux dans le même thread d'exécution, l'instruction de mise en veille arrêtera l'atelier de test et le chargement WebBrowser.

Terminer le code de constructeur de Form1 en joignant les contrôles utilisateur à l'objet Form :

// Form1
  this.Text = "Lightweight Web Application Windows Forms Test Harness";
  this.Size = new Size(500, 710);
  this.Controls.Add(wb);
  this.Controls.Add(button1);
  this.Controls.Add(listBox1);
} // Form1()

Ensuite je code de la méthode de gestionnaire d'événements pour le contrôle bouton sur le harnais de Windows Forms qui lance l'automation de test :

private void button1_Click(object sender, EventArgs e) {
  listBox1.Items.Add(
    "Loading Web app under test into WebBrowser control");
  wb.Url = new Uri(
    "http://localhost/ColorApp/default.html");
}

Après l'ouverture d'un message, j'ai demander le contrôle WebBrowser pour charger l'application Web en cours de test en définissant la propriété d'URL du contrôle. Notez que j'ai codé en dur l'URL de l'application testée. La technique que je présente ici est mieux adaptée pour l'automation de test légère et à usage unique où les valeurs des paramètres codés en dur ont moins d'inconvénients que dans les situations où votre automation de test doit être utilisée sur une longue période de temps.

Ensuite, je commence le code de la méthode ExerciseApp qui accepte le contrôle de l'exécution lorsque l'événement DocumentCompleted est déclenché :

private void ExerciseApp(object sender, EventArgs e) {
  Thread thread = new Thread(new
    ThreadStart(WatchForAndClickAwayMessageBox));
  thread.Start();

La méthode ExerciseApp contient la plupart de la logique d'atelier de test réel. Je commence en générant une nouvelle thread associé à une méthode définie par le programme nommée WatchForAndClickAwayMessageBox. L'idée ici est que lorsqu'une boîte de dialogue modale est générée par l'application Web en cours de test dans le contrôle WebBrowser, l'exécution de tous les tests harnais sera interrompue jusqu'à ce que cette boîte de message est traitée, ce qui signifie que l'atelier de test ne peut pas traiter directement avec la boîte de message. Par conséquent, en met à tourner sur un thread séparé qui surveille une zone de message, l'atelier peut gérer indirectement avec la boîte de message.

Ensuite j'enregistrer un message et puis simuler un utilisateur cliquant sur le clic de l'application Web Me bouton :

listBox1.Items.Add(
  "Clicking on 'Click Me' button");
HtmlElement btn1 = 
  wb.Document.GetElementById("button1");
btn1.InvokeMember("click");

La méthode GetElementById accepte l'ID d'un élément HTML qui fait partie du document chargé dans le contrôle WebBrowser. La méthode InvokeMember peut servir à lancer les événements clic et mouseover. Dans la mesure où aucun texte n'est dans le contrôle TextBox1 de l'application Web, l'application Web génère la boîte de message d'erreur qui va être traitée par le faisceau de méthode WatchForAndClickAwayMessageBox, comme je l'expliquerai bientôt.

Maintenant, en supposant que la boîte de message a été traitée, je continue le scénario de test :

listBox1.Items.Add("Waiting to click away message box");
listBox1.Items.Add("'Typing' roses into TextBox1");
HtmlElement tb1 = wb.Document.GetElementById("TextBox1");
tb1.InnerText = "roses";

J'utilise la propriété InnerText pour simuler un utilisateur tapant “ roses ” dans le contrôle TextBox1. Les autres propriétés utiles pour la manipulation de l'application Web en cours de test sont OuterText, InnerHtml et OuterHtml.

Mon automation se poursuit en simulant un clic d'utilisateur sur l'application Web de Click Me bouton :

listBox1.Items.Add(
  "Clicking on 'Click Me' button again");
btn1 = wb.Document.GetElementById("button1");
btn1.InvokeMember("click");

Contrairement à la précédente simulée cliquez sur, cette fois-ci il est le texte du contrôle TextBox1, afin que la logique de l'application Web s'affiche du texte du résultat dans le contrôle TextBox2, et l'atelier de test peut vérifier un résultat attendu et une passe de connexion ou Échec de message :

listBox1.Items.Add("Looking for 'red' in TextBox2");
HtmlElement tb2 = wb.Document.GetElementById("TextBox2");
string response = tb2.OuterHtml;
if (response.IndexOf("red") >= 0) {
  listBox1.Items.Add("Found 'red' in TextBox2");
  listBox1.Items.Add("Test scenario result: PASS");
}
else {
  listBox1.Items.Add("Did NOT find 'red' in TextBox2");
  listBox1.Items.Add("Test scenario result: **FAIL**");
}

Notez que la réponse HTML ressemblera à < input type = valeur ” texte ” = ” rouge ” / >, c'est pourquoi j'utilise la méthode IndexOf pour rechercher le contenu OuterHtml pour le bon résultat attendu.

Voici la définition de la méthode qui traitera de la boîte de dialogue modale d'application Web :

private void WatchForAndClickAwayMessageBox() {
  IntPtr hMessBox = IntPtr.Zero;
  bool mbFound = false;
  int attempts = 0;
  string caption = "Message from webpage";
.
.
.

Je déclare un handle de la boîte de message, une variable Boolean à faites-moi savoir lors de la boîte de message a été trouvé, une variable de compteur afin que je peux limiter le nombre de fois que mon atelier de recherche pour la boîte de message éviter une boucle sans fin et la légende de la boîte de message à rechercher. Bien que dans ce cas, la légende de la boîte de message est assez évidente, vous pouvez toujours utiliser l'outil Spy ++ pour vérifier la propriété caption de n'importe quel contrôle de la fenêtre.

J'ai ensuite du code une boucle regardent :

do {
  hMessBox = FindWindow(null, caption);
  if (hMessBox == IntPtr.Zero) {
    listBox1.Items.Add("Watching for message box .
.
. "
);
    System.Threading.Thread.Sleep(100);
    ++attempts;
  }
  else {
    listBox1.Items.Add("Message box has been found");
    mbFound = true;
  }
} while (!mbFound && attempts < 250);

J'utilise un - while boucle pour essayer à plusieurs reprises obtenir un handle à un message. Si le retour de FindWindow IntPtr.Zero, j'ai temporisation secondes 0,1 et incrémenter le compteur de ma tentative boucle. Si le retour n'est pas IntPtr.Zero, je sais j'ai obtenu un handle de la boîte de message et je peux quitter le - while boucle. Le “ tentatives <condition 250 ” limitera la quantité de temps que mon atelier est en attente d'une zone de message s'affiche. En fonction de la nature de votre application Web, vous souhaiterez peut-être modifier la durée du retard et le nombre maximal de tentatives.

Après le - while issues de la boucle, j'aurai terminé la méthode WatchForAndClickAwayMessageBox en vérifiant si la sortie s'est produite car une boîte de message a été trouvée ou parce que l'atelier a expiré :

if (!mbFound) {
  listBox1.Items.Add("Did not find message box");
  listBox1.Items.Add("Test scenario result: **FAIL**");
}
else { 
  IntPtr hOkBtn = FindWindowEx(hMessBox, IntPtr.Zero, null, "OK");
  ClickOn(hOkBtn );
}

Si la zone de message n'a pas été trouvée, j'ai classer ceci comme une défaillance du scénario de test et ouvrir une session que le résultat. Si la zone de message a été trouvée, j'utilise la méthode FindWindowEx pour obtenir le handle du contrôle enfant de bouton OK situé sur le contrôle de zone de message parent, puis appeler une méthode définie par programme une application d'assistance nommée ClickOn que je définis en tant que :

private void ClickOn(IntPtr hControl) {
  uint WM_LBUTTONDOWN = 0x0201;
  uint WM_LBUTTONUP = 0x0202;
  PostMessage1(hControl, WM_LBUTTONDOWN, 0, 0);
  PostMessage1(hControl, WM_LBUTTONUP, 0, 0);
}

Le Windows message constantes 0201h et 0202h représentent respectivement gauche de la souris à bouton down et de gauche-souris-bouton-up. J'utilise la méthode PostMessage1 qui est liée à la fonction PostMessage de Win32 API, ce qui j'ai décrit précédemment.

Mon atelier de test se termine en définissant le faisceau de point d'entrée de la méthode main :

[STAThread]
private static void Main() {
  Application.Run(new Form1());
}

Après avoir enregistré mon atelier de test comme Harness.cs, j'ai utilisé le compilateur de ligne de commande. Je lance l'invite de commandes Visual Studio spéciale (qui sait où le compilateur c# csc.exe est), accédez au répertoire maintenant mon fichier Harness.cs et exécutez la commande :

C:\LocationOfHarness> csc.exe /t:winexe Harness.cs

L'argument /t:winexe indique au compilateur de générer un exécutable plutôt que de l'application de console par défaut exécutable Windows Forms. Le résultat est un fichier nommé Harness.exe, ce qui peut être exécuté à partir de la ligne de commande. Comme je l'ai mentionné précédemment, vous souhaiterez probablement utiliser Visual Studio plutôt que le bloc-notes pour créer l'automation de test basé sur le contrôle WebBrowser.

Synthèse

L'exemple que j'ai présenté ici devrait vous donner suffisamment d'informations pour vous aider à écrire votre propre automation de test basé sur le contrôle navigateur Web. Cette technique est idéale pour les scénarios d'automatisation léger : Si vous voulez que pour votre automation de test en cours d'exécution rapidement et où l'automatisation a une durée de vie courte attendue. La puissance de cette technique est sa capacité à traiter les boîtes de dialogue modale, ce qui peut être relativement difficile lors de l'utilisation des autres approches d'automation de test de l'interface utilisateur. Cette technique est particulièrement utile lorsque vous testez les fonctionnalités d'application Web qui sont générée essentiellement par JavaScript côté client.

Dans les situations où Web de fonctionnalités de l'application sont générée par le client-serveur plusieurs allers-retours, vous devrez peut-être modifier le code que j'ai présenté, car chaque fois qu'une réponse est retournée à partir du serveur Web, l'événement DocumentCompleted sera déclenché. L'une des approches permettant de gérer cela consiste à créer et utiliser une variable qui effectue le suivi du nombre d'événements DocumentCompleted et ajoute la logique de branchement pour votre atelier.

Dr.James McCaffrey  travaille pour Volt Information Sciences Inc., où il gère la formation technique d'ingénieurs logiciels travaillant sur le Microsoft Redmond, Washington, campus. Il a travaillé sur plusieurs produits Microsoft, y compris Internet Explorer et MSN Search.Dr.McCaffrey est l'auteur de “ .NET Test Automation Recipes ” (Apress, 2006) et peut être contacté à jammc@microsoft.comde .

Nous vous remercions pour les experts techniques Microsoft suivants pour la révision de cet article : Paul Newson et Dan Liebling