Tipps, Tool-Vergleiche, How-To’s und Tutorials gezielt zu bestimmten Testwerkzeugen

Ihr wollten schon immer eine mobile Anwendung mit Appium automatisieren, wisst aber nicht wie ihr am besten loslegt?

In unserem Appium Tutorial zeigen wir euch die wichtigsten Schritte auf dem Weg zum ersten automatisierten Test mit Appium.

In diesem Beitrag geht es los mit dem Teil 1: Einrichtung von Appium und Android Studio unter Windows.

 

Weiterlesen

Testautomatisierung mit Cypress vs. Selenium Cypress und Selenium sind bekannte Testwerkzeuge, die für die Automatisierung von Webapplikationen eingesetzt werden. Selenium ist ein Open-Source-Automatisierungsframework, das in unterschiedlichen Produktversionen vorhanden ist.  Die Automatisierungslösung Selenium existiert schon seit 2004 und ist ein etabliertes Produkt mit einer großen Nutzerbasis weltweit. Das End-to-End-Tool Cypress hingegen ist seit 2014 ein Newcomer auf dem Markt, welches sich wie Selenium für die Automatisierung von Webapplikationen eignet. Cypress hat in den letzten Jahren durch seine […]

Vor einigen Jahren haben wir in einem unserer Blog Beiträge für die Lösungsmöglichkeit berichtet, wie man auf HTML 5 Seiten Drag & Drop Testautomatisierung mit HTML 5 implementeiren kann.

Der Hintrgrund war, dass die offizielle Selenium Drag & Drop API aus der Actions Klasse auf HTML 5 Seiten nicht richtig funktioniert und selbst die Referenz-Implementierungen von W3C Standard nicht autoamtisieren kann. Der zugehörige Bug-Request für Selenium Web Driver wurde bereits im Jahr 2012 angelegt. Leider ist er nach inzwischen 8 Jahren immer noch ungelöst 🙁

Da die Notwenigkeit der Drag & Drop Testautomtisierung mit Selenium aufgrund von immer komplexer Geschäftsapplikationen im Web immer häufiger angefragt wird, haben wir die Drag&Drop Implementeirung auf GitHub als Open Source Projekt bereitgestellt und ein fertiges Nuget Paket für C# veröffentlicht.

Im Rahmen dieser Implementierung wird die bereits beschriebene alternative Drag & Drop Umsetzung mit einem JavaScript umgesetzt, das automatisch augerufen wird.

Bei der Verwendung von Nuget Paket für Drag&Drop kann die Testautomatisierung von Drag&Drop in nur wenigen Schritten realisiert werden:

  1. Drag & Drop Nugen Paket SeleniumDragDrop in C# Solution einbinden
  2. Quell- und Ziel-Elemente für Drag & Drop auf der Web Seite finden
  3. DragDropHelper instanzieren
  4. Drag & Drop Operation für Quell- und Ziel-Elemente aufrufen

Die Automatisierung von Drag&Drop auf der W3C Refernz-Seite für HTML 5 Drag & Drop kann damit etwa wie folgt aussehen:

    IWebDriver driver = new ChromeDriver(Environment.CurrentDirectory);
    try
    {
        driver.Navigate().GoToUrl("https://www.w3schools.com/html/html5_draganddrop.asp");

        IWebElement sourceEl = driver.FindElement(By.Id("drag1"));
        IWebElement targetEl = driver.FindElement(By.Id("div2"));

        SeleniumDragDrop.DragDropHelper dragdrop = new SeleniumDragDrop.DragDropHelper(driver);
        dragdrop.DragAndDrop(sourceEl, targetEl);

        Assert.IsNotNull(targetEl.FindElement(By.Id("drag1")));
    }
    finally
    {
        driver.Quit();
    }

Viel Spaß beim Ausprobieren.

Aktuelles Windows 10 Update sorgt für Systemabstürze bei Android Entwicklern.

 

Der schnellste und einfachste Weg mit einer Testumgebung für Appium zu starten, ist die Verwendung von einem Android Emulator. Allerdings hat sich mit dem Windows 10 Update (KB4549949) ein Bug eingeschlichen. Er macht das Benutzen des Android Emulators bzw. des AVD-Managers nahezu unmöglich. Nachdem ein Emulator z.B.: In Android Studio gestartet wird, reagiert Windows zuverlässig mit einem Bluescreen (BsoD). Auch andere Emulatoren scheinen betroffen.

 

Es gibt aber eine schnelle Abhilfe: Wird das Update deinstalliert, laufen die Emulatoren wieder einwandfrei.
Das problematische Update wurde am 14.04.2020 veröffentlicht und es gibt noch keinen offiziellen Fix dafür.
Aktuell gibt es noch keine elegantere Lösung als die Deinstallation.

Selenium Framework bietet per sé sehr einfache Möglichkeit an die Tests mit unterschiedlichen Web Browsern durchzuführen und damit die Cross-Browser Test Strategie umzusetzen. Während die Einbindung von gängigen Browsern wie Chrome oder Firefox i.d.R. unproblematisch erfolgt, gilt es bei der Einbindung von Edge und Internet Explorer einige Besonderheiten zu beachten, die in diesem Blog zusammengefasst werden. Die Lösungen werden nachfolgend mit C# aufgezeigt. Die Vorgehensweise ist aber auch auf andere Sprachen wie Java übertragbar.

Weiterlesen

Angular Applikationen auf Ebene von Unit Tests und Integrationstests durchzutesten, ist eine relativ bequeme Geschichte. Gerüchten zu Folge wurde Angular bei Google von einem Test Team entwickelt und so ist die Testbarkeit der Applikation sozusagen direkt in der DNA der Architektur integriert.
Aber wie sieht es mit den E2E Tests aus? Wie werden Cross-Browser Tests im Rahmen einer Angular Applikation realisiert? Dieses Tutorial wird diese Punkte beleuchten.

Einrichtung der Umgebung

Als erstes sollten wir uns die Entwicklungsumgebung einrichten, Angular installieren, uns ein neues Angular Projekt erstellen und uns ansehen, welche Möglichkeiten zur Qualitätssicherung Angular von Haus aus mitbringt und wie speziell die E2E UI Testskripte aufgebaut sind.

Entwicklungsumgebung

Am sinnvollsten ist es, den Code der Applikation in einer IDE (Integrated Development Environment) zu öffnen. Eine IDE ist zwar nicht zwingend notwendig, um mit Angular oder automatisierten Tests zu arbeiten, bietet aber einige Vorteile im Vergleich zu einem simplen Editor (wie Notepad++), z.B. integrierte Git Anbindung, Organisation des Codes und der dazugehörigen Pakete, integrierte Autovervollständigung (Intellisense), integrierter Terminal (Batch / Powershell) und vieles mehr.  Solltest du mit Windows, Mac oder Linux arbeiten, eignet sich die Open Source Entwicklungsumgebung Visual Studio Code gut für diese Aufgabe, aber auch mit der kostenlosen Version von Visual Studio Community für Windows oder Mac, macht man nicht viel falsch. Ich verwende für dieses Tutorial Visual Studio Code.

Um Visual Studio Code zu installieren, lade es einfach  von der offiziellen Webseite runter, installiere und starte die Applikation: https://code.visualstudio.com/

Füge anschließend den Ordner „C:\tutorial\“ im Explorer zu dem Arbeitsbereich hinzu.

Angular Projekt in Visual Studio Code

Schon kannst du den Inhalt von dem Ordner und seine demnächst folgenden Source Dateien einsehen und bearbeiten. Ein weiterer Vorteil ist auch das integrierte Terminal unten, so können wir dort anschließend bequem Pakete installieren oder Tests starten:

  Tipp: Sollte Terminal nicht sichtbar sein, einfach „STRG+ö“ drücken bzw über das Menü View>Terminal auswählen.

Installation von Angular auf dem Rechner

Solltest du davor Angular noch nie auf deinem Rechner installiert haben, benötigst du zwei Sachen:

1.Intalliere Nodejs mit dem dazugehörigen NPM (Node Package Manager). Diesen findest du auf der offiziellen Webseite von NodeJS: https://nodejs.org/en/download/ – wichtig bei NodeJS ist natürlich die Installation vom npm package manager und das „Add to Path“, damit der npm Befehl aus dem Terminal bzw. der Konsole funktioniert

Node.JS Setup
Nodejs Installation

2.Installiere anschließend über NPM die Angular Client Applikation global auf deinem Rechner. Dazu kannst du nach der NodeJs Installation einfach folgende Anweisung in deiner Console bzw. in dem Visual Studio Code Terminal ausführen:

 npm install -g @angular/cli 

Erstellung des ersten Angular Projektes

Nach der Installation von Angular können wir unser erstes kleines Projekt erstellen. Dazu einfach den „ng new <projekt-name>“ aufrufen. Dieses habe ich bei mir project2 genannt.

 ng new project2 

Mit dem Projekt wird ein neuer Ordner mit der kompletten Angular Applikationsstruktur angelegt. Nach der Anlage ist das Angular Projekt sofort lauffähig. In der Ordnerstruktur wird dir vielleicht direkt unter dem Hauptverzeichnis bereits ein Ordner e2e Tests auffallen. Die Testdateien werden bei der Neuanlage eines Angular Projektes immer mit angelegt und enthalten bereits vorkonfigurierte Karma Unit Tests sowie fertig vorkonfigurierte Protractor Tests. Bequemer kann man Testautomatisierung einem Entwickler nicht näher bringen! 🙂

Du kannst auch sofort nach der Anlage aus dem Root Verzeichnis den Befehl „ng e2e“ bzw „npm run e2e“ ausführen.

 ng e2e 

Das Ergebnis sieht bei einem Erstprojekt etwa so aus:

Angular E2E Tests starten

Wie du schon mitbekommen hast, wurde auf dem Rechner die Angular Applikation gebaut, der Chrome Browser gestartet und die Applikation aufgerufen, außerdem wurde ein erster Check auf einen Titel durchgeführt. Der Aufruf ng e2e ist wirklich sehr bequem, da es uns eine Menge Arbeit abnimmt. Würden wir die gleiche Kette „manuell“ machen wollen, müssten wir folgende Aktionen unternehmen:

  1. Angular Applikation bauen und starten mit dem Befehl ng serve in einer eigenen Konsole
  2. Start vom Webdriver Manager mit webdriver-manager start in einer eigenen Konsole (evtl. sollte davor noch webdriver-manager update durchgeführt werden)
  3. Start der Testfälle mit dem Befehlt protractor e2e/protractor.conf.js in einer weiteren Konsole

Was die einzelnen Befehle bedeuten und welche weiteren Möglichkeiten existieren, Testfälle auszuführen, schauen wir uns etwas weiter unten an.

Struktur und Aufbau der E2E Tests in Angular

Der erste UI Test war ja schon erfolgreich, obwohl wir dazu auch noch überhaupt nichts beigetragen haben. Aus diesem Grund schauen wir uns jetzt die einzelnen Komponenten der E2E Testfälle an und wie diese in den Testskripten realisiert werden.

Als erstes schauen wir uns die beteiligten Komponenten an. Das Standard Testframework in Angular ist Jasmine. Aus diesem werden die Testfälle über das Testautomation Tool Protractor mit einem Selenium Webdriver im Hintergrund durchgeführt.

Jasmine

Jasmine ist ein sogenanntes Behavior-Driven Development Testing Framework, dass viele hilfreiche Funktionalitäten bereitstellt, die im Rahmen der Testdurchführung auf unterschiedlichen Schichten (Unit Tests / Integrationstests und auch E2E UI Tests) immer wieder benötigt werden, z.B. zur Verifizierung von Soll / Ist Ergebnissen.

Behavior Driven bedeutet, dass die Test Suiten und Test Cases so spezifiziert werden, dass sie das fachliche Soll-Verhalten der Applikation beschreiben, wodurch es auch für außenstehende einfacher ist, die Testinhalte und Ziele zu verstehen.

Der Aufbau einer typischen Jasmine „Test Suite“ sieht eigentlich immer so aus:

describe("A suite", function() {
it("contains spec with an expectation", function() {
expect(true).toBe(true);
});
});

Describe entspricht einer TestSuite und kann in sich mehrere it’s enthalten.
Ein it entspricht einem Testfall welches in sich eine Logik enthält, die z.B. prüft ob etwas dem erwarteten Wert entspricht
Die Struktur ist etwas gewöhnungsbedürftig, lässt sich aber nach einer Zeit tatsächlich ganz gut lesen.

Protractor

Protractor ist die offizielle UI Bibliothek für Angular UI Testfälle. Protractor ist eigentlich nichts anderes, als ein Wrapper für den Selenium Webdriver. Im Endeffekt benutzt man also Selenium zur Browserautomatisierung, mit dem Vorteil, die für Angular spezifischen Methoden von Protractor als Wrapperfunktionen nutzen zu können.

E2E Ordnerstruktur

Wenn wir uns den erstellten Ordner ansehen, finden wir darin folgende Dateien

C:\tutorial\project2\e2e\protractor.conf.js
C:\tutorial\project2\e2e\tsconfig.e2e.json
C:\tutorial\project2\e2e\src\app.e2e-spec.ts
C:\tutorial\project2\e2e\src\app.po.ts

Die tsconfig.e2e.json werden wir an dieser Stelle vorerst auslassen, da diese lediglich für die TypeScript Konfiguration zuständig ist (eine kurze Anleitung dazu kommt demnächst). Die anderen Dateien sollten wir uns aber detaillierter anschauen:

Testkonfigurationsdatei protractor.conf.js

Die Datei protractor.conf.js ist der Kern der E2E Automatisierung. Diese ist für die Konfiguration der Protractor Ausführung verantwortlich und definiert u.a. welche Testspezifikationen ausgeführt werden, z.B.:

specs: [
  './src/**/*.e2e-spec.ts'
],

Mit welchen Capabilities (Art des Browsers, Einstellungen des Browsers) z.B.:

capabilities: {
'browserName': 'chrome'
},

welche Jasmine Optionen gelten, welcher Reporter verwendet wird, welche Timeouts die Skripte enthalten und vieles vieles mehr. Eine genaue Auflistung der unterschiedlichen Möglichkeiten findest du unter: https://github.com/angular/protractor/blob/master/docs/api-overview.md#config-file

Diese Datei werden wir dann noch in weiteren Szenarien anpassen und erweitern.

Jasmine Testfallspezifikationsdatei src/app.e2e-spec.ts

Die Datei enthält die Jasmine Spezifikation der „Testsuiten“ und „Testfälle“. Der Verweis auf app.po ist interessant, weil dort die sogenannte Page Object Implementierung hinterlegt ist. Mehr dazu im nächsten Abschnitt

import { AppPage } from './app.po'; //Import von Page Object AppPage aus der datei src/app.po.ts
 
describe('workspace-project App', () => { // neue TestSuite
  let page: AppPage; //globale AppPage Variable, verfügbar für alle Its
 
  beforeEach(() => { //Jasmine "Init" Klasse, diese wird jedes mal ausgeführt, bevor ein 'it' ausgeführt wird
    page = new AppPage(); //Erstellung neuer Instanz der der Page Object Klasse AppPage
  });
 
  it('should display welcome message', async () => { //neuer Testfall
    await page.navigateTo(); //Aufruf einer Page Object Funktion, mit der zu der Startseite navigiert wird
    expect(await page.getParagraphText()).toEqual('Welcome to testapp!'); //überprüfung ob der Paragraph Text dem erwarteten Wert "Welcome to testapp!" entspricht
  });
});

Page Object Implementierung src/app.po.ts

Die Datei stellt das Page Object bzw. „funktionale Abstraktion“ der tatsächlichen Protractor Zugriffe auf die Elemente einer Webseite dar. In dieser werden also die einzelnen Elemente gesucht und über Protractorfunktionalitäten angesteuert.

import { browser, by, element } from 'protractor'; // importiert benötigte Funktionalitäten aus dem Protractor Modul

export class AppPage { // exportiert die Klasse, die von anderen Klassen konsumiert und genutzt werden kann
async navigateTo() { //Navigationsmethode
await browser.get('/'); //Ruft über protractor die "baseadress" Adresse auf, die in protractor.conf.js hinterlegt ist
}

async getParagraphText() {
await element(by.css('app-root h1')).getText(); //sucht mit Hilfe von css Identifier ein Element mit dem Tag h1 und gibt den Text von diesem Element zurück.
}
}

Aufbau des Angular Tutorial Projektes

Nachdem wir den grundsätzlich Aufbau eines E2E Tests angeschaut haben, möchten wir eine etwas komplexere Anwendung nehmen, mit der wir anschließend unsere Testfälle entwickeln und anschließend mit unterschiedlichen Konfigurationen testen werden. Dazu nehmen wir einfach das auf der Angular Hauptseite https://angular.io/tutorial/toh-pt0 aufgeführte Beispiel. Da es bei diesem Tutorial nicht um den Aufbau einer Angular Anwendung geht, laden wir einfach die fertige Angular Applikation von der Tutorialseite runter:

Links zu dem finalen Review findest du hier: https://angular.io/tutorial/toh-pt6#final-code-review
Und die Zip Datei kann hier bezogen werden: https://angular.io/generated/zips/toh-pt6/toh-pt6.zip

Solltest du die komplette Anwendung selbst aufbauen möchten, folge einfach dem sehr gut beschriebenen Tutorial auf der angular.io Webseite.

Ich habe für dieses Tutorial ein neues Verzeichnis auf C: mit dem Namen „tutorial“ angelegt, dorthin die zip Datei runtergeladen und anschließend die zip Datei in einen weiteren Unterordner mit der Bezeichnung „angular_heroes“ entpackt.

Anschließend wechseln wir in das Anwendungsverzeichnis und führen npm install aus, um die benötigten Pakete für unsere Angular Anwendung zu installieren:

 cd C:\tutorial\angular_heroes
npm install

Damit sollten sich die erforderlichen Pakete installieren lassen.  Am Ende müsste in etwa folgende  Meldung erscheinen:

 
added 1113 packages from 1279 contributors and audited 34260 packages in 70.961s
found 14 vulnerabilities (9 low, 5 high)
run `npm audit fix` to fix them, or `npm audit` for details
 

Tipp: Sollte npm install mal nicht beim ersten mal erfolgreich durchlaufen, einfach noch einmal probieren. Ab und zu gibt es da Probleme beim Download von phantomjs oder anderen Paketen.

Nun müssten wir die Applikation starten können, dazu einfach in den angular_heroes Ordner gehen und mit ng-serve starten:

ng serve --open

Mit dem –open Parameter wird die Applikation nach Start in dem Standard Browser geöffnet.

Nach diesem Befehl sollte sich dein Browser mit der URL http://localhost:4200/dashboard öffnen und du müsstest das im Angular Tutorial gezeigte „Dashboard“ sehen. Mach Dich ruhig ein paar Minuten mit der Applikation vertraut, bevor wir mit der automatisierten Qualitätssicherung dieser Applikation loslegen.

Wichtig: Da die Angular Leute ja bekannt für ihre Begeisterung für testbare Anwendungen / Testautomatisierung sind, haben sie natürlich schon etliche Testfälle für das Tutorial Projekt hinzugefügt. Du kannst dir natürlich gerne die E2E Testfälle der Entwickler anschauen und diese auch gerne mit npm run e2e ausprobieren. Ich würde allerdings kurz bitten den Ordner „src“ zu löschen bzw. außerhalb der Applikation zu verschieben und einen neuen, leeren Ordner src anzulegen, damit wir die Testfälle gleich komplett neu in der Page Objects Struktur aufbauen können.

Aufbau der UI Testautomatisierung für das Angular Projekt

Da wir nun ein funktionierendes „System Under Test“ haben, können wir uns überlegen, welche Testfälle dafür relevant sind. Am besten geht das natürlich direkt in der Jasmine BDD Notation. Daher starten wir hier einfach mit dem „Verhalten“ in dem Spec File.

Erstellung der Jasmine Spec File(s)

Wir legen uns in dem Ordner src eine Datei an. Im Visual Studio Code klicke einfach rechts auf den Ordner im Explorer und wähle „New File“ aus.

Wir betrachten einfach die beiden Views der Appliaktion und unterteilen sie in „Verhalten / Eigenschaften, die wir Testen möchten.

Beim Dashboard könnten wir z.B. prüfen ob:

  • der Titel „Tour of Heroes“ ist
  • die 4 Top Heroes angezeigt werden
  • die Navigation verfügbar ist und aus Dashboard und Heroes besteht

Bei der Hero View könnten wir prüfen ob:

  • Die Liste der Helden existiert
  • wir einen neuen Helden anlegen können
  • wir einen Helden löschen können

Die dazugehörige Jasmine Struktur könnte daher so aussehen:

describe('Heroes Dashboard', ()=> {
    it(' should have "Tour of Heroes" as title',()=> {
 
    });
    it(' should contain 4 Top Heroes',()=> {
 
    });
 
    it(' should have a navigation',()=> {
 
    });
 
});
 
describe('Heroes ', ()=&amp;gt;{
    it(' view contains a list of heroes',()=> {
 
    });
 
    it(' creation is possible',()=> {
 
    });
 
    it(' deletion is possible',()=> {
 
    });
});

Wenn wir jetzt npm run e2e ausführen, sollte die Ausgabe so aussehen:

Jasmine started
Heroes Dashboard
√  should have "Tour of Heroes" as title
√  should contain 4 Top Heroes
√  should have a navigation

Heroes
√  view contains a list of heroes
√  creation is possible
√  deletion is possible
Executed 6 of 6 specs SUCCESS in 0.023 sec.

Die Testfälle machen an der Stelle natürlich überhaupt nichts. Aber wir sehen schon mal, dass Jasmine mit unserer Struktur arbeiten und die „it“ Anweisungsblöcke problemlos aufrufen kann.

Erstellung der dazugehörigen PageObjects

Die Page Objects Dateien sollten Funktionen und Hilfsfunktionen der Businesslogik einer View abbilden. Deshalb legen wir uns nun eine weitere Datei in das Verzeichnis e2e/src an, die wir  dashboard.po.ts nennen. Ich werde die verwendeten Funktionen mit den dazugehörigen Links zu der Protractor Hilfe versehen, damit du dir gleich die offizielle Beschreibung ansehen kannst inkl. der Rückgabewerte der Funktionalität und dir natürlich auch angewöhnst, bei neuen Funktionen die zugehörige Hilfe zu verwenden.

Page Objects Datei dashboard.po.ts

Um das Verhalten der View testen zu können, könnten wir z.B. in der dazugehörigen Page Object Datei folgende Funktionen anlegen:

  1. Zu der View navigieren
  2. Liste mit Top Helden zurückgeben
  3. Title auf dem Dashboard zurückgeben
  4. Die Namen der Navigationselemente als Array zurückgeben

Rückgabe vom Titel und die Navigation zur Seite ist an sich relativ einfach, wir könnten uns eigentlich komplett den beiden Funktionen navigateTo und getTitle aus dem neuen e2e Projekt bedienen.
Die navigateTo Methode ruft lediglich browser.get(‚/‘) auf, womit der Browser angewiesen wird, die baseAddress (aus protractor.conf.js) aufzurufen.
Die getTitle Methode sieht schon etwas komplizierter aus: dort wird mit element(by.css(‚app-root h1‘)) ein Element gesucht und mit getText() anschließend der innerText von diesem Element zurückgegeben.

Auch die beiden anderen Funktionen sehen ähnlich aus, nur verwenden wir dafür dann die Suche nach mehreren Elementen mit dem Befehl element.all. Dieser Befehl liefert uns eine Art Array zurück (zur Synchronisierungt kommen wir gleich), welches 0 bis n Elemente enthalten kann, die mit den Kriterien gefunden bzw nicht gefunden wurden. Bei der Liste mit den Navigationsnamen nutzen wir die gleiche element.all Funktion, nur bekommt diese am Ende noch die Map Funktion, die eben nur die Texte aus den Daten extrahiert und uns den dazugehörigen „Texte“ zurück gibt.


import { browser, by, element, ElementFinder } from 'protractor';
  
export class DashboardPage {
 async navigateTo() {
    await browser.get('/');
  }

 async getTopHeroes(){
    return await element.all(by.css('app-root app-dashboard > div h4'));
  }
  
  async getDashboardTitle() {
    return await element(by.css('app-root h1')).getText();
  }

  async getNavigationItemNames() {
    return await element.all(by.css('app-root nav a')).map((el: ElementFinder) =><strong>;</strong> el.getText()); 
  }
}

Page Objects Datei heroes.po.ts

Um die Funktionen der Heroes Sicht abdecken zu können, würden sich folgende Methoden anbieten:

  • Liste von den Heroes zurückgeben
  • Einen neuen Hero anlegen
  • Einen Hero löschen
import { browser, by, element, ElementFinder } from 'protractor'; 
  
export class HeroesPage { 
  async navigateTo() { 
    await browser.get('/heroes'); 
  }
 
  async getHeroList(){
    return await element.all(by.xpath('//app-heroes/ul'));
  }
  
  async addHero(name:string) { 
    await element(by.xpath('//app-heroes//input')).sendKeys(name);
    await element(by.xpath('//button[text()=" add "]')).click();
    return await element(by.xpath('//app-heroes/ul//*[contains(text(),"'+name+'")]'));
  }
 
  async deleteHero(name:string) { 
   await element(by.xpath('//app-heroes/ul//*[contains(text(),"'+name+'")]/../button[@title="delete hero"]'));
    return await element.all(by.xpath('//app-heroes/ul//*[contains(text(),"'+name+'")]'));
  }
}

Implementierung der automatisierten E2E Testfälle

Nachdem die Funktionalität implementiert ist, wollen wir diese aus unseren Jasmine Spec Testfällen aufzurufen. Aber erst mal wird es etwas theoretischer:

Asynchronität in der Testautomatisierung mit JavaScript / Protractor

Solltest du bisher mit Selenium in Java oder C# gearbeitet haben, sollte dir der Code sehr bekannt vorkommen. Der vertraute Eindruck täuscht an dieser Stelle aber. Wir arbeiten mit Javascript / Typescript und natürlich auch mit Protractor asynchron. Wie die Hilfe von element(by.css(‚app-root h1‘)) schon anmerkt, gibt die Suche einen sogenannten „ElementFinder“ und nicht ein WebElement wie in C# / Java zurück. Dieses kann zwar für die meisten Funktionen wie ein WebElement verwendet werden, enthält aber auch die Besonderheit, dass die Funktionen eben nicht synchron ausgeführt werden, sondern erst dann, wenn der ElementFinder das dazugehörige Element auch gefunden hat. Wenn du dir auch erneut z.B. getText() als Funktion anschaust, wirst du feststellen, dass diese keinen String Wert zurückliefert, sondern einen Promise, der „verspricht“ irgendwann einen String Wert zu liefern. In diesem Fall heißt es, dass wenn du z.B. den Wert von getText() in die Konsole ausgeben möchtest, dieser zwingend einen await bzw. .then zur Synchronisierung benötigt, z.B.:

await element(by.tagName('h1')).getText().then(function(wert){ console.log(wert); })

Das muss man im Hinterkopf behalten, funktioniert aber problemlos, wenn man etwas javascript / typescript Erfahrung mitbringt bzw. Interesse hat, sich in dieses Thema einzuarbeiten.

Spec File mit Aufrufen der Page Objects

Aber nun kommen wir zu der Spec Datei, diese würde nun am Ende so aussehen:

import { DashboardPage } from './dashboard.po';
import { HeroesPage } from './heroes.po';
 
 
describe('Heroes Dashboard', () => {
    let dashboardPage;
 
    beforeAll(() => {
        dashboardPage = new DashboardPage();
    });
    beforeEach(async () => {
        await dashboardPage.navigateTo();
    });
 
 
    it('should have "Tour of Heroes" as title', async () => {
        expect(await dashboardPage.getDashboardTitle()).toEqual("Tour of Heroes");
    });
 
    it('should contain 4 Top Heroes', async () => {
       await dashboardPage.getTopHeroes().then(function (arr) {
            expect (arr.length).toEqual(4);
        })
    });
 
    it('should have Dashboard and Heroes in Navigation List', async () => {
       await dashboardPage.getNavigationItemNames().then((arr) => {
            expect (arr.length).toEqual(2);
            expect (arr[0]).toEqual("Dashboard");
            expect (arr[1]).toEqual("Heroes");
        })
 
    });
 
});
 
describe('Heroes ', () => {
    let heroesPage;
 
    beforeAll(() => {
        heroesPage = new HeroesPage();
    });
 
    beforeEach(async() => {
        await heroesPage.navigateTo();
    });
 
 
    it('view contains a list of ten heroes', async () => {
       await heroesPage.getHeroList().then((arr) => {
            expect(arr.length).toEqual(10);
 
        })
    });
 
    it(' creation is possible', async () => {
        //neuen Helden anlegen
        let neuerHeld = heroesPage.addHero("SuperTester");
        //prüfen ob der Held neben einer neuen ID auch den richtigen Namen enthält
        expect(await neuerHeld.getText()).toContain("SuperTester");
 
        //Bonus: Asyonchronität, hier geben wir die Liste aller Helden aus:
        heroesPage.getHeroList().then((helden) =&amp;gt; {
            for (let held of helden) {
                held.getText().then((heldenname) =&amp;gt; {
                    console.log(heldenname);
                })
            }
        });
 
        //und hier die Demonstration der Asynchronität von Protractor:
        console.log("Dieser Text wird in der Console früher ausgegeben, als die Liste der Helden ;-)");
 
    });
 
    it(' deletion is possible', async () => {
        await heroesPage.deleteHero("SuperTester").then((arr) => {
            expect(arr.length).toEqual(0);
        })
 
    });
});

Damit sind unsere ersten automatisierten E2E Testfälle der Angular Applikation fertig.

Starte die Testdruchführung mit

 ng e2e 

und überprüfe die Testergebnisse.

Der Test-Code ist natürlich noch nicht perfekt und könnte noch weiter verfeinert werden. Er demonstriert aber ganz gut, wie die Testautomatisierung mit Protractor in einem Angular Umfeld grundsätzlich realisiert werden kann. Ich habe auch eine kleine Demo der Asynchronität in die Specs eingebaut, um zu verdeutlichen wie der „Executor“ vorgeht.

Zusammenfassung

In diesem Tutorial haben wir gelernt, wie man sehr schnell eine funktionierende state-of-the-art  E2E Testautomatisierungslösung einer Angular Applikation mit Hilfe der automatisch generierten Vorlage in einem Angular Projekt aufsetzen kann. In dieser Vorlage haben wir Jasmin Framework verwendet, um eine Testspezifikation mit Hilfe der behavior-driven Notation zu definieren. Anschliessend haben wir das selenium-basierte Testautomatisierungsframework Protractor verwendet, um die konkreten Aktion dieser Testspezifikation zu automatisieren. Am Schluss haben wir die integrierte Testlaufzeitumgebung von Angular verwendet, um bequem die Testdurchführung unserer Tstsuite mit einem einzigen Befehl zu starten.

Ich werde demnächst weitere Beiträge zu dem Thema Testautomatisierung im Angular Umfeld hinzufügen, u.A.

  • Durchführung von E2E Protractor Tests in der CI Pipeline
  • Durchführung der E2E Testfälle in der Cloud (z.B. mit BrowserStack)
  • Mocken von Rest API um isoliert Oberflächen testen zu können
  • und evtl. einiges mehr.

Schaue daher regelmäßig vorbei 😉


Hat dir dieses Tutorial gefallen? Fehlt noch etwas oder du kommst an einigen Stellen nicht weiter? Bitte teile uns dein Feedback in den Kommentaren mit.

 

Im Testing Center von Microsoft Test Manager findet sich der Tab ‚Organize‘ unter dem sich vier Sub-Tabs finden.

Obwohl man sich laut den Breadcrumps in einem bestimmten Testplan befindet, werden in den vier Sub-Tabs per default alle Entitäten (Test Pläne, Test Konfigurationen, Testfälle, Shared Steps) innerhalb des TFS Team Projekts angezeigt, was einigermaßen verwirrend ist.
Weiterlesen

Seit Firefox 52 gibt es eine Besonderheit:
Wenn auf einer Webseite ohne HTTPS (SSL Zertifikat), ein Passwort eingetippt wird, erscheint folgende Warnung: This connection is not secure. Logins entered here could be compromised.

Das Ganze ist natürlich sehr sinnvoll, denn das Passwort wird in diesem Fall im Klartext  übertragen und kann z.b. in nicht gesicherten WLAN-Netzen mit einfachsten Mitteln ausgelesen werden.

In der Testautomatisierung bereitet uns dieses „Tooltipp“ aber ab und zu Probleme.
Denn was passiert, wenn der dazugehörige Login Button direkt unter dem Passwortfeld ist? Richtig! Statt auf den Button zu klicken, erfolgt der Klick auf die Warnung und diese leitet uns auf die Seite „https://support.mozilla.org/en-US/kb/insecure-password-warning-firefox“ weiter. Das hat natürlich einen fehlgeschlagenen Testfall zur Folge.

Hier ein Tipp wie diese Warnung ausgeschaltet werden kann:

Weiterlesen

Nachdem die Selenium Conference in London bereits fast 4 Monate her ist und die nächste bereits in wenigen Wochen statt findet, möchte ich meine persönliche Top 5 der Präsentationen vorstellen, die keiner verpassen sollte, der in der beruflich oder privat mit der Testautomatisierung beschäftigt.
Weiterlesen

Es ist offiziell, die Hölle ist zugefroren!!!

So oder so ähnlich hat es einer der Erfinder von Appium auf der Selenium Konferenz 2016 in London verkündet. Der Grund ist relativ simpel. Microsoft hat sich entschieden den Coded UI Ansatz nicht weiter zu fahren und auf den generischen Selenium / Appium WebDriver Ansatz zu setzen. Weiterlesen