Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Testen der Benutzeroberfläche von Webanwendungen mittels jQuery
James McCaffrey
Die jQuery-Bibliothek ist eine Open-Source-Sammlung von JavaScript-Funktionen. Obwohl jQuery für die Webentwicklung erstellt wurde, verfügt die Bibliothek über verschiedene Eigenschaften, die sie für die einfache Automatisierung von Tests der Benutzeroberfläche von Webanwendungen geeignet machen. In der Kolumne für diesen Monat zeige ich Ihnen, wie dies funktioniert.
Um einen besseren Eindruck vom Thema dieses Artikels zu bekommen, betrachten Sie den Screenshot in Abbildung 1. Dieser zeigt die Automatisierung von Benutzeroberflächentests mittels jQuery. Die Testumgebung wird von Internet Explorer gehostet und besteht aus einer HTML-Seite mit dem Namen „UITestHarness.html“.
Die Testseite ist lediglich ein Container, der zwei HTML-Rahmenelemente enthält. Der rechte Rahmen enthält die Webanwendung, die getestet werden soll, in diesem Fall eine einfache, jedoch repräsentative ASP.NET-Rechneranwendung namens MiniCalc. Der linke Rahmen enthält eine HTML-Seite namens „TestScenario001.html“ mit einem TextArea-Element für die Anzeige von Fortschrittsmeldungen, einem Button-Element für den manuellen Start der Automatisierung sowie jQuery-basierten JavaScript-Funktionen für die Bearbeitung der getesteten Webanwendung und die Prüfung des Ergebnisstatus für die Anwendung, um festzustellen, ob die Anwendung den Test bestanden hat oder nicht.
Abbildung 1 Automatisierung von Benutzeroberflächentests mittels jQuery
Die jQuery-Bibliothek ist außerdem gut für Tests von Antworten auf http-Anfragen geeignet. Ich habe das Testen der Anfrageantwortzeiten mittels jQuery in der Test Run-Kolumne aus dem Januar 2010 behandelt (msdn.microsoft.com/magazine/ee335793).
In diesem Artikel wird angenommen, dass Sie über grundsätzliche Kenntnisse der ASP.NET-Technologie und fortgeschrittene JavaScript-Programmierkenntnisse haben. Es wird nicht vorausgesetzt, dass Sie über Erfahrungen mit der jQuery-Bibliothek verfügen. Auch wenn Ihnen ASP.NET und die Testautomatisierung neu sind, sollten Sie in der Lage sein, den Ausführungen der Kolumne für diesen Monat ohne große Schwierigkeiten zu folgen.
In den folgenden Abschnitten beschreibe ich zunächst die MiniCalc-Anwendung, sodass Sie genau wissen, in welchem Verhältnis die Implementierung der getesteten Anwendung zum automatisierten Benutzeroberflächentest steht. Anschließend erkläre ich Ihnen die Details der Erstellung eines einfachen automatisierten Benutzeroberflächentests auf der Basis von jQuery, wie in Abbildung 1 gezeigt. Zum Schluss werde ich beschreiben, wie Sie die vorgestellten Techniken auf Ihre eigenen Anforderungen anwenden können. Außerdem bespreche ich die Vor- und Nachteile der Automatisierung von Benutzeroberflächentests mittels jQuery im Vergleich zu anderen Verfahren. Ich bin der Meinung, dass die hier vorgestellten Techniken interessant sind und eine sinnvolle Ergänzung Ihrer Tools für das Testen, die Entwicklung und die Verwaltung darstellen können.
Die getestete Anwendung
Betrachten wir den Code für die MiniCalc-Webanwendung auf der Basis von ASP.NET, für die ich einen automatisierten Benuteroberflächentest mittels jQuery durchführen werde.
Ich habe die MiniCalc-Anwendung mit Visual Studio 2008 erstellt. Nach dem Starten von Visual Studio habe ich auf Datei | Neu | Website geklickt. Um den CodeBehind-Mechanismus von ASP.NET zu vermeiden, sodass der gesamte Code meiner Webanwendung in einer einzigen Datei enthalten ist, habe ich die Option für die leere Website ausgewählt. Als Nächstes habe ich in der Dropdownliste im Feld für den Speicherort den HTTP-Modus ausgewählt (und nicht den Dateimodus) und den Speicherort wie folgt angegeben:
http://localhost/TestWithJQuery/MiniCalc
Ich entschied mich für die Verwendung von C# für die MiniCalc-Anwendungslogik. Die hier vorgestellten Techniken für die Testautomatisierung funktionieren mit ASP.NET-Webanwendungen, die mit C# und Visual Basic erstellt wurden, sowie mit Webanwendungen, die mit Technologien wie klassischem ASP, CGI, PHP, JSP, Ruby usw. erstellt wurden.
Im Dialogfeld für die neue Website habe ich auf „OK“ geklickt, um IIS zu konfigurieren und die Struktur meiner Webanwendung zu generieren. Als Nächstes habe ich im Projektmappen-Explorer mit der rechten Maustaste auf den Projektnamen „MiniCalc“ geklickt und im Kontextmenü die Option für das Hinzufügen eines neuen Objekts ausgewählt. Ich wählte in der Liste der installierten Vorlagen „Webformular“ aus und akzeptierte „Default.aspx“ als Dateinamen. Ich entfernte die Markierung für die Option für die Platzierung des Codes in einer eigenen Datei und klickte anschließend auf die Schaltfläche zum Hinzufügen.
Als Nächstes führte ich einen Doppelklick auf den Dateinamen „Default.aspx“ im Projektmappen-Explorer aus, um den vorlagengenerierten Code in den Text-Editor zu laden. Ich löschte den gesamten Vorlagencode und ersetzte diesen durch den in Abbildung 2 gezeigten Code.
Abbildung 2 Getestete MiniCalc-Webanwendung – Quelle
<%@ Page Language="C#" %>
<script runat="server">
static Random rand = null;
private void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
rand = new Random(0);
}
private void Button1_Click(object sender, System.EventArgs e)
{
int randDelay = rand.Next(1, 6); // [1-5]
System.Threading.Thread.Sleep(randDelay * 1000);
int x = int.Parse(TextBox1.Text);
int y = int.Parse(TextBox2.Text);
if (RadioButton1.Checked)
TextBox3.Text = (x + y).ToString("F4");
else if (RadioButton2.Checked)
TextBox3.Text = (x * y).ToString("F4");
}
</script>
<html>
(client-side JavaScript and UI elements here)
</html>
Um den Quellcodes kurz und leicht verständlich zu halten, ließ ich die normale Fehlerprüfung aus. Der vollständige Quellcode für die MiniCalc-Anwendung und die Testumgebung ist auf code.msdn.microsoft.com/mag201012TestRun verfügbar.
Um automatisierte Tests für Webanwendungen zu erstellen, müssen Sie in den meisten Fällen die IDs der Benutzersteuerelemente kennen. Wie in Abbildung 2 gezeigt, verwende ich TextBox1 und TextBox2 für zwei Integerwerte für Benutzereingaben – RadioButton1 und RadioButton2 für die Auswahl von Addition oder Multiplikation – und TextBox3 für die Ergebnisse der mathematischen Berechnungen.
Wenn ein Benutzer auf das Button1-Steuerelement klickt, wird die Ausführung der MiniCalc-Anwendung zunächst um ein bis fünf Sekunden verzögert, um eine serverseitige Verarbeitung zu simulieren. Anschließend wird entweder die Summe oder das Produkt aus den beiden Benutzereingabewerten berechnet und angezeigt.
Als Nächstes gestaltete ich die MiniCalc-Anwendung mittels der AJAX-Technologie asynchron. Dazu benötigte ich eine web.config-Datei für die Anwendung. Anstatt eine web.config-Datei manuell neu zu erstellen, drückte ich die F5-Taste, um Visual Studio anzuweisen, die Anwendung zu kompilieren und den Debugger auszuführen. Als ich von Visual Studio aufgefordert wurde, das Hinzufügen einer web.config-Datei zu genehmigen, klickte ich auf „OK“. Anschließend fügte ich der MiniCalc-Anwendung ein serverseitiges ScriptManager-Steuerelement hinzu, um AJAX zu aktivieren:
<asp:ScriptManager ID="sm1" runat="server" EnablePartialRendering="true" />
Danach fügte ich die für die asynchrone Aktualisierung des TextBox3-Ergebniselements in Verbindung mit dem Button1-Klickereignis benötigten Tags hinzu:
<asp:UpdatePanel ID="up1" runat="server">
<ContentTemplate>
<p><asp:TextBox id="TextBox3" width="120" runat="server" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
Bei genauer Betrachtung von Abbildung 1 können Sie erkennen, dass ich einen clientseitigen Lifezähler in der Benutzeroberfläche platziert habe, um die Tatsache hervorzuheben, dass es sich bei MiniCalc um eine AJAX-Anwendung handelt. Wenn eine asynchrone Anfrage an MiniCalc zurückgegeben wird, wird nur TextBox3 aktualisiert, und der Lifezähler wird nicht zurückgesetzt. Das pageLife-Textfeld wird wie folgt definiert:
<input type="text" id="pageLife" size="1"/>
Der verknüpfte clientseitige JavaScript-Code ist:
<script language="javascript">
var count = 0;
function updatePageLife() {
++count;
var tb = document.getElementById("pageLife");
tb.value = parseInt(count);
window.setTimeout(updatePageLife, 1000);
}
</script>
Der Zähler wird durch das Onloadereignis der Anwendung gestartet:
<body bgColor="#ccffff" onload="updatePageLife();">
Testen der Benutzeroberfläche von Webanwendungen mittels jQuery
Sie haben nun die getestete Webanwendung kennengelernt. Lassen Sie uns nun den Code für die Automatisierung des Benutzeroberflächentests betrachten. Die Haupttestumgebung ist einfach eine normale HTML-Seite mit zwei Rahmenelementen:
<html>
<!-- UITestHarness.html -->
<head>
<title>Test Harness for MiniCalc AJAX Web App</title>
</head>
<frameset cols="45%,*" onload="leftFrame.appLoaded=true">
<frame src="http://localhost/TestWithJQuery/TestScenario001.html"
name="leftFrame" >
<frame src="http://localhost/TestWithJQuery/MiniCalc/Default.aspx"
name="rightFrame">
</frameset>
</html>
Der Rahmen mit dem Namen „rightFrame“ hostet die getestete Webanwendung ohne Modifizierungen oder Testinstrumentierungen. Der Rahmen mit dem Namen „leftFrame“ hostet eine HTML-Seite namens „TestScenario001.html“, die den gesamten jQuery-Code für die Testautomatisierung enthält. Beachten Sie, dass bei Eintreten des Onloadereignisses für das Rahmenelement eine Variable in der leftFrame-Seite namens „appLoaded“ auf „Wahr“ gesetzt wird. Diese Variable wird verwendet, um sicherzustellen, dass der automatisierte Test nicht gestartet wird, bevor die getestete Webanwendung vollständig in die Testumgebung geladen wurde. Die Struktur des Codes für das Testszenario wird in Abbildung 3 gezeigt.
Abbildung 3 Struktur der Seite für den automatisierten Benutzeroberflächentest
<html>
<!-- TestScenario001.html -->
<head>
<script src='http://localhost/TestWithJQuery/jquery-1.3.2.js'></script>
<script type="text/javascript">
$(document).ready(function() {
logRemark("jQuery Library found and harness DOM is ready\n");
} );
var testScenarioID = "Test Scenario 001";
var maxTries = 20;
var numTries;
var polling = 500; // milliseconds
var appLoaded = false;
var started = false;
function launch() {
if (!started)
runTest();
}
function waitUntilAppLoaded() {
// Code
}
function runTest() {
// Start automation
}
function step1() {
// Manipulate state
}
function clickCalculate() {
// Click the Calculate button
}
function checkControl(controlID, controlVal) {
// Determine if control has specified value
}
function step2() {
// Manipulate state
}
function callAndWait(action, checkControlFunc, controlID, controlVal,
callbackFunc, pollTime) {
// The heart of the automation
}
function doWait(checkControlFunc, controlID, controlVal,
callbackFunc, pollTime) {
// Wait until Web app responds
}
function finish() {
// Determine pass/fail result
}
function logRemark(comment) {
// Utility logging function
}
</script>
</head>
<body bgcolor="#F5DEB3">
<h3>This is the UI test scenario with jQuery script page</h3>
<p>Actions:</p><p><textarea id="comments" rows="22" cols="34">
</textarea></p>
<input type="button" value="Run Test" onclick="runTest();" />
</body>
</html>
Das Testskript beginnt mit dem Verweis auf die jQuery-Bibliothek:
<script src='http://localhost/TestWithJQuery/jquery-1.3.2.js'>
Hier zeige ich auf eine lokale Kopie der jQuery-Bibliothek, die ich von der jQuery-Projektwebsite heruntergeladen (jquery.com) und in das Rootverzeichnis der MiniCalc-Anwendung kopiert habe. Ich habe jQuery 1.3.2 verwendet. Die Bibliothek wird ständig weiterentwickelt, sodass zu dem Zeitpunkt, zu dem Sie diesen Artikel lesen, wahrscheinlich eine neuere Version verfügbar sein wird. Weitere Informationen zu den Verweisen auf die jQuery-Bibliothek in Ihrem Code finden Sie unter „So erhalten Sie die jQuery-Bibliothek“.
So erhalten Sie die jQuery-Bibliothek
Es gibt mehrere Speicherorte, an denen Sie die jQuery-Bibliothek für Ihre Anwendung finden können. Wie erwähnt, können Sie die neueste Version von jquery.com herunterladen und vom lokalen Dateisystem aus verwenden. Auf der jQuery-Website sind Downloads für die Entwicklung (nicht komprimiert) und die Produktion (minimiert – durch die Entfernung von Leerzeichen – um den Speicherplatzbedarf zu reduzieren) verfügbar. Wählen Sie das gewünschte Paket aus, und speichern Sie die JS-Datei im Projektverzeichnis.
Wenn der Anwendungshost über eine aktive Internetverbindung verfügt, können Sie einfach auf die aktuellste Version von jQuery in einem Bereitstellungsnetzwerk für Onlineinhalte (Content Delivery Network, CDN) verweisen. Es gibt eine Reihe von Quellen, die Sie verwenden können (einschließlich einer eigenen gehosteten Version). Zwei hoch verfügbare CDNs sind jedoch Microsoft AJAX Content Delivery Network (asp.net/ajaxlibrary/cdn.ashx) und Google Libraries API (code.google.com/apis/).
Sie können beispielsweise mittels des folgenden Skripttags auf die minimierte Version von jQuery im Microsoft Ajax CDN verweisen:
<script
src="https://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js"
type="text/javascript">
</script>
Scott Guthrie hat einen nützlichen Blog über die Verwendung von Microsoft Ajax CDN für jQuery und ASP.NET AJAX unter tinyurl.com/q7rf4w veröffentlicht.
Im Allgemeinen gilt, dass die Verwendung einer in der Testumgebung gespeicherten, nicht komprimierten Kopie der Bibliothek zuverlässiger ist als die Verwendung einer gehosteten oder komprimierten Kopie, wenn jQuery für automatisierte Tests verwendet wird. Für Produktionszwecke sollten Sie jedoch eine zuverlässig gehostete Bibliothek verwenden.
Als Nächstes verwende ich einen jQuery-Standardausdruck, um festzustellen, ob meine Automatisierung auf die jQuery-Bibliothek zugreifen kann:
$(document).ready(function() {
logRemark("jQuery Library found and harness DOM is ready\n");
} );
Die jQuery-Bereitschaftsfunktion wird gestartet, wenn das entsprechende DOM-Dokument vollständig in den Speicher des Testhosts geladen wurde und alle DOM-Elemente verfügbar sind. Wenn kein Zugriff auf die jQuery-Bibliothek möglich ist – was in der Regel dann der Fall ist, wenn Sie einen nicht korrekten Pfad für die Bibliothek angegeben haben – wird der Fehler „Objekt erwartet“ ausgelöst.
Die Bereitschaftsfunktion akzeptiert eine anonyme Funktion als ihren einzigen Parameter. Anonyme Funktionen werden häufig für automatisierte Tests verwendet, sowohl für jQuery als auch für JavaScript. Sie können sich eine anonyme Funktion als eine Funktion vorstellen, die vorübergehend mittels des Funktionsschlüsselworts definiert wird.
Im Folgenden sehen Sie ein Beispiel für eine Funktion mit dem Namen logRemark:
function logRemark(comment) {
var currComment = $("#comments").val();
var newComment = currComment + "\n" + comment;
$("#comments").val(newComment);
}
In dieser Situation definiere ich eine Funktion, die eine programmdefinierte Protokollierungsfunktion namens „logRemark“ aufruft, um die Nachricht in der Testumgebung anzuzeigen, dass jQuery verfügbar ist. Ich kann auch die systeminterne JavaScript-Benachrichtigungsfunktion verwenden.
Ich beginne, indem ich den jQuery-Selektor verwende und die Syntax verkette, um den aktuellen Text im Textbereich mit ID-„Kommentaren“ zu platzieren. Die $-Notation dient als Verknüpfungsalias für die jQuery-Metaklasse. Die #-Syntax wird für die Auswahl eines HTML-Element auf der Basis der ID verwendet, und die val-Funktion kann sowohl zum Festlegen als auch zum Abrufen eines Werts (einer Eigenschaft in objektorientierter Programmierterminologie) verwendet werden. Ich füge dem vorhandenen Kommentartext den comment-Parameter und ein Zeichen für eine neue Zeile hinzu und verwende anschließend die jQuery-Syntax, um das TextArea-Element zu aktualisieren.
Als Nächstes lege ich einige globale Variablen für den automatisierten Test fest.
var testScenarioID = "Test Scenario 001";
var maxTries = 20;
var numTries;
var polling = 500;
var appLoaded = false;
var started = false;
Da meine Automatisierung eine asynchrone Anwendung betrifft, verwende ich keine zufälligen zeitlichen Verzögerungen. Stattdessen verwende ich eine Folge kurzer (durch variable Abrufe definierter) Verzögerungen, die wiederholt (numTries-Variable) geprüft werden, um festzustellen, ob der Wert eines HTML-Elements eine Boolesche Bedingung erfüllt. Die Anzahl der Versuche ist begrenzt (maxTries-Variable). In diesem Testszenario verzögere ich um maximal 20 Versuche bei einer Verzögerung von 500 ms pro Versuch für eine Gesamtdauer von 10 Sekunden. Die appLoaded-Variable wird verwendet, um festzustellen, ob die getestete Webanwendung vollständig in die Testumgebung geladen wurde. Die started-Variable wird verwendet, um die Ausführung der Testumgebung zu koordinieren.
Um die Automatisierung manuell zu starten, können Sie auf die Schaltfläche für die Ausführung des Tests klicken:
<input type="button" value="Run Test" onclick="runTest();" />
Die in Abbildung 3 gezeigte Startfunktion wird für die vollständige Testautomatisierung verwendet, wie ich in Kürze zeigen werde. Die runTest-Funktion dient als Hauptfunktion für die Koordinierung der Testautomatisierung:
function runTest() {
waitUntilAppLoaded();
started = true;
try {
logRemark(testScenarioID);
logRemark("Testing 3 + 5 = 8.0000\n");
step1();
}
catch(ex) {
logRemark("Fatal error: " + ex);
}
}
Die runTest-Funktion beginnt mit dem Aufruf der Funktion „waitUntilAppLoaded“, die wie folgt definiert ist:
function waitUntilAppLoaded() {
if (appLoaded == true) return true;
else window.setTimeout(waitUntilAppLoaded, 100);
}
Denken Sie daran, dass das Testszenario die Variable „appLoaded“ als „Falsch“ initialisiert, und dass das Onloadereignis für die Testumgebung die Variable „appLoaded“ auf „Wahr“ setzt. Ich verwende hier die systeminterne setTimeout-Funktion, um wiederholt für 100 ms zu unterbrechen, bis der Wert von „appLoaded“ „Wahr“ ist. Beachten Sie, dass dieser Ansatz dazu führen kann, dass die Verzögerung ständig fortgesetzt wird. Um dies zu verhindern, sollten Sie einen globalen Zähler hinzufügen und nach einer festgelegten maximalen Anzahl von Verzögerungen den Wert „Falsch“ zurückgeben.
Nach der Festlegung der globalen Startvariablen zeigt runTest einige Kommentare an und ruft eine step1-Funktion in einem Wrapper für die Ausnahmebehandlung auf. Die hier vorgestellte Umgebungsstruktur stellt nur eine Möglichkeit dar. Sie können die Umgebung verändern, um sie an Ihren Programmierstil und Ihre Testumgebung anzupassen. Mit meiner Struktur betrachte ich ein Testszenario als eine Folge von Statusänderungen. Jede dieser Statusänderungen wird durch eine stepX-Funktion dargestellt.
Die step1-Funktion verändert den Status der getesteten Webanwendung durch die Simulierung von Benutzereingaben, wie in Abbildung 4 gezeigt.
Abbildung 4 Simulierung von Eingaben mittels der step1-Funktion
function step1() {
logRemark(
"Entering 3 and 5 and selecting Addition");
var tb1 =
$(parent.rightFrame.document).find('#TextBox1');
tb1.val('3');
var tb2 =
$(parent.rightFrame.document).find('#TextBox2');
tb2.val('5');
var rb1 =
$(parent.rightFrame.document).find('#RadioButton1');
rb1.attr("checked", true);
logRemark(
"\nClicking Calculate, waiting for async response '8.0000'");
asyncCall(clickCalculate, checkTextBox3, "8.0000",
step2, polling);
}
Die jQuery-Syntax für den Zugriff auf und die Bearbeitung von HTML-Elementen ist konsistent, elegant und zum größten Teil browserunabhängig. Beachten Sie, dass für den Zugriff auf die im rightFrame-Element geladene Webanwendung vom Code im leftFrame-Element aus das übergeordnete Schlüsselwort verwendet werden muss. Beachten Sie außerdem, dass der jQuery-Suchfilter verwendet werden muss.
Bei den Veränderungen der TextBox1- und TextBox2-Elemente gehe ich davon aus, dass die getestete Webanwendung vollständig in das rightFrame-Element geladen wurde. Diese Annahme ist möglicherweise im Fall von Anwendungen mit langen Ladezeiten nicht vernünftig. In diesen Situationen können Sie den jQuery-Selektorcode in einer window.setTimeout-Verzögerungsschleife platzieren und das Zielobjekt gegen einen integrierten „nicht definierten“ Wert testen.
Da es sich bei der getesteten MiniCalc-Anwendung um eine AJAX-Anwendung handelt, kann die Testumgebung nicht einfach das Klickereignis für die Calculate-Schaltfläche aufrufen. Die Testumgebung würde in diesem Fall die Ausführung fortsetzen, ohne auf die asynchrone Antwort der Anwendung zu warten. Daher verwende ich eine programmdefinierte callAndWait-Funktion:
function callAndWait(action, checkControlFunc, controlID,
controlVal, callbackFunc, pollTime) {
numTries = 0;
action();
window.setTimeout(function(){doWait(
checkControlFunc, controlID, controlVal,
callbackFunc, pollTime);}, pollTime);
}
Die callAndWait-Funktion ruft eine Funktion (den Aktionsparameter) auf, tritt in eine Verzögerungsschleife ein, hält für einen kurzen Moment an (pollTime-Variable) und prüft, ob es einen wahren Anwendungsstatus gibt, indem die Parameterfunktion „checkControlFunc“ mit Argumenten der Parameter „controlID“ und „controlVal“ aufgerufen wird. Wenn „checkControlFunc“ den Wert „Wahr“ zurückgibt oder die maximal zulässige Anzahl von Verzögerungen ausgeführt wurde, wird die Steuerung an eine Parameterfunktion namens „callbackFunc“ übertragen.
Die callAndWait-Funktion arbeitet mit einer programmdefinierten doWait-Funktion zusammen:
function doWait(checkControlFunc, controlID,
controlVal, callbackFunc, pollTime) {
++numTries;
if (numTries > maxTries) finish();
else if (checkControlFunc(controlID, controlVal))
callbackFunc();
else window.setTimeout(function(){
doWait(checkControlFunc, controlID,
controlVal, callbackFunc, pollTime);}, pollTime);
}
Die doWait-Funktion ist rekursiv und wird beendet, wenn „checkControlFunc“ den Wert „Wahr“ zurückgibt, oder der lokale Zähler „numTries“ den Wert der globalen Variablen „maxTries“ überschreitet. Dadurch wird eine Funktion namens „clickCalculate“ aufgerufen, die in eine Verzögerungsschleife eintritt, das Abrufen für 500 ms unterbricht und die Funktion „checkControl“ mit Argumenten von TextBox3 und 8.0000 aufruft, bis „checkControl“ den Wert „Wahr“ zurückgibt oder die Verzögerungsschleife 20-mal ausgeführt wurde (wie von „maxTries“ festgelegt):
callAndWait(clickCalculate, checkControl, "TextBox3",
"8.0000", step2, polling);
Wenn „checkControl“ den Wert „Wahr“ zurückgibt, wird die Steuerung an die Funktion „step2“ übertragen. Die clickCalulate-Funktion verwendet die jQuery-Auswahl und -Verkettung:
function clickCalculate() {
var btn1 = $(parent.rightFrame.document).find('#Button1');
if (btn1 == null || btn1.val() == undefined)
throw "Did not find btn1";
btn1.click();
}
Der Hauptgrund für die Definierung einer Aktionswrapperfunktion wie diese besteht darin, dass die Funktion mittels des Namens an die callAndWait-Funktion übergeben werden kann. Die checkControl-Funktion ist eine einfache Funktion:
function checkControl(controlID, controlVal) {
var ctrl = $(parent.rightFrame.document).find('#' + controlID);
if (ctrl == null || ctrl.val() == undefined || ctrl.val() == "")
return false;
else
return (ctrl.val() == controlVal);
}
Zunächst verwende ich jQuery-Syntax, um einen Verweis auf das Steuerelement zu erhalten, die durch den Parameter „controlID“festgelegt ist. Wenn der Wert des Steuerelements noch nicht verfügbar ist, kehre ich sofort zur Verzögerungsschleife zurück. Wenn das Steuerelement bereit ist, kann ich prüfen, ob es gleich dem durch den Parameter „controlVal“ angegebenen, erwarteten Wert ist.
Nach dem Aufruf der gewünschten Anzahl von stepX-Funktionen übertrage ich die Steuerung an eine finish-Funktion. Diese Funktion stellt zunächst fest, wie sie erreicht wurde:
if (numTries > maxTries) {
logRemark("\nnumTries has exceeded maxTries");
logRemark("\n*FAIL*");
}
else ....
Wenn der Wert der globalen Variablen „numTries“ den Wert von „maxTries“ überschreitet, weiß ich, dass die getestete Webanwendung nicht innerhalb der zulässigen Zeit geantwortet hat. Ich entscheide hier nach dem Zufallsprinzip, dass es sich um einen fehlgeschlagenen Test und nicht um ein unbestimmtes Ergebnis handelt. Wenn der Wert für „numTries“ den Wert für „maxTries“ nicht überschritten hat, beginne ich mit der Prüfung des Endstatus der getesteten Anwendung:
logRemark("\nChecking final state");
var tb1 = $(parent.rightFrame.document).find('#TextBox1');
var tb2 = $(parent.rightFrame.document).find('#TextBox2');
var tb3 = $(parent.rightFrame.document).find('#TextBox3');
Hier rufe ich Verweise für die drei Textfeld-Steuerelemente auf. Welche Elemente der getesteten Webanwendung genau Sie prüfen, ist von den Details Ihrer Anwendung abhängig. Als Nächstes untersuche ich den Wert der einzelnen Textfeld-Steuerelemente, um zu sehen, ob diese den erwarteten Wert haben:
var result = "pass";
if (tb1.val() != "3") result = "fail";
if (tb2.val() != "5") result = "fail";
if (tb3.val() != "8.0000") result = "fail";
In meinem Testszenarioskript sind alle Testeingaben und erwarteten Werte fest kodiert. Die hier vorgestellte Testautomatisierung eignet sich am besten für einfache und schnelle Testszenarien, in denen die Verwendung fest kodierter Daten einfach und effektiv ist.
Die finish-Funktion fasst den Test mittels der Anzeige des Ergebnisses (bestanden oder nicht bestanden) zusammen:
if (result == 'pass')
logRemark("\n*Pass*");
else
logRemark("\n*FAIL*");
Wie im Fall der Testeingabedaten, ist auch dies ein einfacher Ansatz, und Sie sollten die Testergebnisse möglicherweise in eine externe Datei auf dem Testhost oder Webserver schreiben oder per SMTP an eine E-Mail-Adresse senden.
Zusammenfassung
Die hier beschriebene Umgebung ist gewissermaßen semi-automatisiert, da Sie auf eine Schaltfläche klicken müssen, um den Test zu starten. Sie können die Umgebung vollständig automatisieren, indem Sie eine Start-Wrapper-Funktion hinzufügen:
function launch() {
if (!started)
runTest();
}
Fügen Sie dem Rahmenelement in der Umgebungsseite das Attribut „onload=“leftFrame.launch();“ hinzu. Jedes Laden der Webanwendung in die Umgebung löst ein Onloadereignis aus. Daher verwende ich die globale start-Variable, um zu verhindern, dass der automatisierte Test erneut gestartet wird. Obwohl das HTML-Rahmenelement kein Onloadereignis unterstützt, können Sie dennoch ein Onloadattribut im Rahmenelement der Umgebung platzieren. Das Ereignis wird in das übergeordnete Rahmenelement verschoben.
Nun können Sie eine .bat-Datei mit z. B. den folgenden Befehlen erstellen:
iexplore http://localhost/TestWithJQuery/UITestHarness001.html
iexplore http://localhost/TestWithJQuery/UITestHarness002.html
Wenn die .bat-Datei ausgeführt wird – möglicherweise mittels eines Windows-Aufgabenplaners – wird die Umgebung geladen und die Automatisierung automatisch gestartet. Sie können das hier vorgestellte Testsystem auch erweitern, indem Sie die programmdefinierten Funktionen in einem jQuery-Plug-In platzieren.
Bei der Erstellung einfacher Testautomatisierungen für die Benutzeroberflächen von Webanwendungen stehen Ihnen mehrere Alternativen zum hier vorgestellten jQuery-basierten Verfahren bereit. Der Hauptvorteil der Verwendung der jQuery-Bibliothek im Vergleich zu rohem JavaScript besteht darin, dass jQuery mit mehreren Browsern wie Internet Explorer, Firefox und Safari kompatibel ist. Ein anderer wesentlicher Vorteil ist, dass Sie durch die Verwendung von jQuery für die Erstellung von Testautomatisierungen Ihre Kenntnisse von jQuery für die Webentwicklung erweitern können.
Die Verwendung von jQuery hat im Vergleich zu anderen Verfahren auch Nachteile. Die Verwendung von jQuery beinhaltet in gewisser Weise eine Abhängigkeit von externen Tools, und die skriptbasierte Testautomatisierung kann schwieriger zu verwalten sein als die nicht skriptbasierte Testautomatisierung. Im Vergleich zu Testumgebungen wie Selenium oder Watir ermöglicht Ihnen die Erstellung von Testautomatisierungen mittels jQuery eine höhere Flexibilität. Sie müssen den Code jedoch auf einer niedrigeren Abstraktionsebene erstellen.
Wie immer, erinnere ich Sie daran, dass kein einzelner Ansatz für die Testautomatisierung für alle Situation gleich gut geeignet ist. Die Automatisierung von Benutzeroberflächentests für Webanwendungen mittels jQuery kann jedoch in zahlreichen Softwareentwicklungsszenarien eine effiziente und effektive Technik darstellen.
Dr. James McCaffrey arbeitet für Volt Information Sciences Inc. und organisiert technische Schulungen für Softwareentwickler auf dem Campus von Microsoft in Redmond, Washington. Er hat an verschiedenen Microsoft-Produkten mitgearbeitet, unter anderem an Internet Explorer und MSN Search. Dr. McCaffrey ist der Autor von „.NET Test Automation Recipes“ (Apress 2006) und kann unter jammc@microsoft.com erreicht werden.
Unser Dank gilt den folgenden technischen Experten für die Durchsicht dieses Artikels: Scott Hanselman und Matthew Osborn