Eine Einführung in Monkey Testing mit Gremlins.js

Avatar of Alicia Sedlock
Alicia Sedlock am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Ein gängiger Ausspruch in unserer Branche ist: „Man kann nie vorhersagen, wie ein Benutzer Ihr Produkt verwenden wird, sobald er es in den Händen hält.“ Wenn Sie jemals zugesehen haben, wie ein Stakeholder eine Website oder Webanwendung zum ersten Mal benutzt, wissen Sie das vielleicht aus eigener Erfahrung. Ich kann nicht zählen, wie oft ich gesehen habe, wie ein Benutzer scheinbar vergaß, wie er Websites auf einem Mobilgerät benutzen soll, oder versuchte, sie auf eine Weise zu benutzen, die einen denken lässt: „Aber niemand würde so etwas im echten Leben *wirklich* tun!“

Fakt ist, man weiß nie *wirklich*, was ein Benutzer im Moment tun könnte. Er könnte in einem panischen Gemütszustand sein, versuchen, etwas zu schnell zu erledigen, und tippt oder tippt nicht so, wie es ein ruhiger, konzentrierter Benutzer tun würde. Das passt gut in das allzu häufige Szenario, bei dem man für den besten Fall plant und entwickelt und nicht über Grenzfälle nachdenkt oder darüber, „was passiert, wenn die Dinge nicht perfekt in dieser Reihenfolge passieren?“ Als Entwickler neigen wir dazu, Dinge so zu bauen, dass alles verstanden wird, dass der Benutzer rational ist und einfach wissen sollte, dass schnelles Herumtippen etwas Seltsames verursachen könnte. Es kann sogar diejenigen betreffen, die versehentliche Tipp- oder Klickfehler machen, wenn sie einer App nicht volle Aufmerksamkeit schenken – wie oft haben Sie versehentlich auf einem Mobilgerät getippt, als Sie beim Gehen und Sprechen gleichzeitig versucht haben, auf einen Tweet oder eine E-Mail zu antworten.

Das Erstellen von Werkzeugen, die uns helfen, das Unvorhersehbare zu testen, ist nicht ganz neu. Im Jahr 2012 hatte Netflix seinen internen Dienst Chaos Monkey Open-Source gemacht, der „virtuelle Maschineninstanzen und Container beendet, die in Ihrer Produktionsumgebung laufen.“ Einfach ausgedrückt, ist es ein Dienst, der Server zufällig herunterschaltet, um sicherzustellen, dass ein gesamtes System bei einem Ausfall nicht heftig zusammenbricht. Unsere Entwicklungsgemeinschaften erinnern uns auch daran, nicht nur für den „Happy Path“ zu designen, sondern wie können wir unvorhergesehene Ausfallpunkte in unseren Schnittstellen erkennen, so wie wir es mit unseren Serverarchitekturen können?

Wenn hundert Affen an Schreibmaschinen die Werke von Shakespeare schreiben können, dann sollte ein Affe sicherlich Fehler und Probleme in unseren Schnittstellen finden können.

Die Affen ranlassen

Monkey Testing ist eine Testmethode, die zufällige Benutzereingaben generiert – Klicks, Wischgesten, Eingabe von Daten – mit dem alleinigen Zweck, Probleme zu finden oder Ihre Anwendung vollständig zum Absturz zu bringen. Im Gegensatz zu Unit- und Akzeptanztests, bei denen Sie Testfälle schreiben, die in einer bestimmten Reihenfolge oder unter bestimmten Bedingungen ablaufen und dadurch eine Voreingenommenheit in der Testweise Ihrer Schnittstelle erzeugen. Entwickler haben weniger Kontrolle darüber, wie ein Monkey-Test ausgeführt wird, und da er jedes Mal zufällig ausgeführt wird, testen Sie nicht nur ein Szenario, sondern eine unendliche Kombination von Interaktionen.

Obwohl diese Art von Tests für die meisten Technologie-Stacks verfügbar ist, sind webbasierte Systeme noch nicht so weit. Zum Beispiel verfügt das Android SDK über einen UI Exerciser Monkey, der die meisten Benutzeroberflächen- und Systemereignisse verarbeitet. Da Webentwickler zunehmend kritisch über Leistung und Stresstests nachdenken, sind einige dieser Ideen endlich in Form von Gremlins.js, einer JavaScript-basierten Monkey-Testing-Bibliothek des Teams von Marmelab, im Web angekommen.

Affen, Kobolde und andere lustige Viecher

Gremlins.js läuft mit so viel oder so wenig Kontrolle, wie Sie es benötigen. Die anfängliche Einrichtung ist relativ zeitsparend.

Es gibt drei Möglichkeiten, Gremlins.js zu nutzen.

Eigenständige Bibliothek

Der einfachste Weg, die Bibliothek zu integrieren, ist, sie direkt in Ihre Website einzubinden. Dadurch wird gremlins in den globalen Namensraum Ihres Projekts aufgenommen, was bedeutet, dass Sie von überall in Ihrem Projekt darauf zugreifen können.

<script src="path/to/gremlins.min.js"></script>

<script type="javascript">
  // You can also run this in any file now!
  gremlins.createHorde().unleash();
</script>

Require.js-Modul

Wenn Sie Require.js in Ihrem Projekt verwenden, können Sie Gremlins.js nicht-global und nach Bedarf importieren.

require.config({
  paths: {
    gremlins: 'scripts/libraries/gremlins.min'
  }
});

require(['gremlins'], function(gremlins) {
  gremlins.createHorde().unleash();
});

Lesezeichen

Wenn Sie Monkey Testing ad hoc nutzen möchten, gibt es sogar ein Lesezeichen, das ein Ein-Klick-Test auf jeder beliebigen Seite ermöglicht. Sie können das Lesezeichen unter den Installationsanweisungen herunterladen.

Rumspielen

Wenn Sie sich für die direkte Einbindung der Bibliothek oder den Import über Require entschieden haben, können Sie jetzt mit Gremlins herumspielen! In unseren Installationsbeispielen rufen wir gremlins.createHorde().unleash() auf – was macht das also?

gremlins           // Yo, Gremlins
  .createHorde()   // Create me a default horde
  .unleash();      // Then immediately release them

Sehen Sie den Pen Gremlins.js out of the box von Alicia Sedlock (@aliciasedlock) auf CodePen.

Die Standard-Horde enthält alle fünf verfügbaren Arten von zufällig generierten Benutzerinteraktionen, auch bekannt als „Gremlin-Arten“, die Folgendes umfassen:

  • formFillerGremlin füllt Formulare mit Daten, klickt auf Checkboxen/Radio-Buttons und interagiert mit anderen Standard-Formularelementen
  • clickerGremlin klickt überall auf das sichtbare Dokument
  • toucherGremlin berührt überall auf das sichtbare Dokument
  • scrollerGremlin scrollt das Viewport
  • typerGremlin löst zufälliges Tippen auf einer simulierten Tastatur aus

Bei der Auslösung hinterlassen Gremlins eine visuelle Anzeige auf dem Bildschirm für die ausgeführte Aktion. Sie hinterlassen auch ein Protokoll der ausgeführten Aktionen, das in der Entwicklerkonsole zu finden ist, zusammen mit zusätzlichen Daten, die mit der jeweiligen Art verbunden sind. Sie sehen dann etwa so aus wie im folgenden Beispiel.

gremlin formFiller input 5 in <input type=​"number" name=​"age">​
gremlin formFiller input [email protected] in <input type=​"email" name=​"email">​
gremlin clicker    click at 1219 301
gremlin scroller   scroll to 100 25

Standardmäßig werden Gremlins in 10-Millisekunden-Intervallen und insgesamt 1000 Mal zufällig ausgelöst.

Neben unseren „bösen“ Gremlins, die gerne Ärger machen, gibt es auch hilfreiche Gremlins, Mogwais genannt. Sie stören unsere Anwendung nicht wie Gremlins, sondern berichten hauptsächlich darüber, wie unsere Anwendung standhält, z. B. indem sie die aktuelle Bildrate protokollieren. Mogwais lösen Fehler aus, wenn die Bildrate unter 10 fällt.

mogwai  fps  12.67
mogwai  fps  23.56
err > mogwai  fps  7.54 < err
mogwai  fps  15.76

Die Kombination aus Gremlin- und Mogwai-Protokollierung liefert ein gutes Bild von allem, was während des Tests passiert ist.

Ohne viel Anpassung bietet Gremlins.js sofort eine ziemlich robuste Testsuite.

Fortgeschrittenes Herumspielen

Wenn die Standardkonfiguration nach der Verwendung nicht ausreicht, gibt es eine ganze Reihe von Möglichkeiten, die Ausführung anzupassen. Zum Beispiel möchten Sie sich vielleicht nur auf bestimmte Komponenten auf einer Seite konzentrieren, anstatt immer eine ganze Seite zu testen.

Obwohl wir nicht alle Gremlin-Arten auf bestimmte Bereiche beschränken können, können wir toucher, clicker und formFiller auf bestimmte Bereiche unserer Seite zu einem bestimmten Zeitpunkt anwenden. Insbesondere bitten wir einen Gremlin, das Elternelement eines Elements zu überprüfen, auf das er abzielt. Wenn sich dieses Element innerhalb unseres definierten Bereichs befindet, fährt der Gremlin mit der Aktion fort. Andernfalls versucht der Gremlin erneut, ein Element zum Interagieren zu finden. Wir können dem Gremlin auch mitteilen, wie oft er versuchen soll, die Aktion auszuführen, bevor er aufgibt, mit maxNbTries.

gremlins.species.clicker().canClick(function(element) {
    return $(element).parents('.my-component').length;
    /**
       Is the element this gremlin attempted to click
       within our wanted scope? Let it proceed by
       returning true! Otherwise, tell it to try again
       by returning false.
    **/
}).maxNbTries(5); // Our gremlin will tolerate 5 false returns for canClick before it gives up and moves on

// Similarly, we can control the scope of formFiller and toucher.

gremlins.species.formFiller.canFillElement(/** do stuff here **/);
gremlins.species.toucher.canTouch(/** do stuff here **/);

Sehen Sie den Pen Gremlins.js out of the box von Alicia Sedlock (@aliciasedlock) auf CodePen.

Benutzerdefinierte Gremlins

Wenn Sie sich durch die Auswahl der verfügbaren Gremlin-Arten eingeschränkt fühlen, keine Angst! Sie können Ihre eigenen benutzerdefinierten Gremlins schreiben, um beliebige andere Aktionen auszuführen, die Sie von Benutzern erwarten. Möchten Sie zum Beispiel prüfen, was passiert, wenn ein Benutzer versucht, ein Formular zufällig an einem beliebigen Punkt seiner Erfahrung abzuschicken? Sie können hoffen, dass clicker zufällig auf unseren Submit-Button klickt, oder Sie können einen benutzerdefinierten Submission-Gremlin erstellen, um Ihre Chancen zu erhöhen und die Ausführung zu steuern.

Dies erfordert ein gewisses Verständnis dafür, wie man DOM-Ereignisse in JavaScript erstellt und anpasst. Lassen Sie uns also die Teile durchgehen, die für die Erstellung eines Submission-Gremlins notwendig sind.

gremlins.createHorde() // first, create our horde 
  .allGremlins()      // and enable all gremlins
  .gremlin(function() {

    // Now let's define our submission gremlin
    var targetElement, availableForms;

    availableForms = document.querySelectorAll('form'); // Let's get all available form elements on the page
    targetElement = availableForms[Math.floor(Math.random()*availableForms.length)]; // Then let's grab a random element from those results

    // Now, we create a dummy submission event
    var evt = document.createEvent('HTMLEvents');  // Create an event container
    evt.initEvent('submit');  // Define our event as a submit event
    targetElement.dispatchEvent(evt);  // Finally, dispatch the submit event onto our randomly selected form

    // We also want to make sure to log this event like others gremlins do!      
    console.log('gremlin submit ', targetElement);
  })
  .unleash();

Sehen Sie den Pen Customized gremlin with Gremlins.js von Alicia Sedlock (@aliciasedlock) auf CodePen.

Wenn Sie weitere Anleitungen zur Erstellung benutzerdefinierter Ereignisse wünschen, schauen Sie sich die Dokumentation von Mozilla Developer Network zur Erstellung von Ereignissen an und werfen Sie unbedingt einen Blick auf den Quellcode, wie Gremlins.js seine Ereignisse erstellt (der Clicker-Gremlin ist ein guter Anfang).

Horden "seeden"

Das Ausführen einer neuen Horde jedes Mal, wenn Sie diese Art von Test durchführen, hilft, Ihre Benutzeroberfläche in vielen verschiedenen Szenarien zu belasten. Wenn Sie jedoch eine Horde entfesseln und Fehler auftreten, wie sollen Sie dann wirklich wissen, ob Sie die Fehler behoben haben, die diese Fehler verursacht haben?

Für Fälle, in denen Sie dieselbe Horde mehrmals ausführen möchten, können Sie die Horde "seeden". Dies gibt Ihnen jedes Mal, wenn Sie den Test ausführen, genau dieselbe Horde.

var horde = gremlins.createHorde();
horde.seed(1234);
horde.unleash();

Sie sollten abwägen, wie oft Sie geseedete Horden im Vergleich zu zufälligen Horden in einer langfristigen Lösung verwenden. Während geseedete Horden Wiederholtests ermöglichen, liegt ein großer Teil des Nutzens von Monkey Testing in seiner Zufälligkeit, die in einem Szenario, in dem immer derselbe Seed verwendet wird, etwas müßig wird.

Fazit

Die Web-Community spricht oft davon, keine Annahmen über unsere Benutzer zu treffen. Sie haben möglicherweise langsame Verbindungen, kein ganz aktuelles Gerät oder sind auf eine Weise beeinträchtigt, die die von ihnen verwendete Website zugänglich machen muss. Wir können auch nicht versprechen, dass die fünfjährige Jaime nicht das Telefon ihrer Eltern schnappt, wild zu tippen beginnt und erhebliche Probleme mit dem, was sie gerade benutzt, verursacht. Oder Kassidy aus dem Marketing, die nach den ersten Händen am Produkt aufgeregt oder in Aufregung tippt. Die Reihenfolge, Geschwindigkeit oder Wiederholung einer Benutzeraktion kann nicht vorhergesagt werden. Als Entwickler sind wir unseren Benutzern schuldig, sicherzustellen, dass unsere Dienste nicht unerwartet kaputt gehen, nur weil wir davon ausgehen, dass sie nur "Happy Path"-Aktionen ausführen.

Die Auswahlmöglichkeiten für clientseitiges Monkey Testing sind begrenzt, aber Gremlins.js beherrscht die Grundlagen von Anfang an. Wie bei jeder Art von Testbibliothek oder Framework können wir sie nur verbessern, wenn Leute sie benutzen! Sie suchen aktiv nach Mitwirkenden. Wenn Sie also eine Wunschliste mit Dingen haben, die diese Bibliothek tun kann, lassen Sie es sie wissen!