20. Juni 2016 · von Steffen Nörtershäuser

UI Tests mit Visual Studio Team Services und PhantomJS

Um die Qualität in unseren Projekten auf einem hohen Niveau zu halten, setzen wir UI Tests ein, gekoppelt mit einem automatisierten Deployment, der bei jedem Commit von Änderungen Fehler sofort aufzeigt, welche anschließend behoben werden können.

Eingesetzte Technologien

Für Continous Integration nutzen wir Visual Studio Team Services von Microsoft. Diese Lösung ist zusammen mit entsprechenden Powershell Skripten eine automatisierte Build und Deployment Lösungen.

Für UI Tests setzen wir PhantomJS ein. PhantomJS ist ein headless Browser, der leicht zu automatisieren ist und nahezu den vollen Umfang von Googles Chrome Webbrowser bereitstellt. Sowohl der Chrome Webbrowser, als auch der PhantomJS basieren beide auf der freien WebKit – HTML Rendering-Engine. Ausnahmen lassen sich auf dieser Seite finden.

Das Beispiel

Als Beispiel für diesen Artikel soll eine SharePoint Lösung mit einer zugehörigen Datenbank deployed werden und die Seiten anschließend mit PhantomJS auf Fehler untersucht werden.

Automatisierte Builds

Der erste Schritt in diesem Beispiel ist das Einrichten eines automatisierten Builds auf dem Build Server. Ein solcher Build wird automatisch ausgeführt, sobald ein Entwickler eine Änderung in das zentralisierte Quellcode Verwaltungssystem (in diesem Beispiel Git) eincheckt.

Um einen solchen Build einzurichten, wählt man in den Visual Studio Team Services den Reiter „Build“ und fügt einen neuen Build mit einen Klick auf das grüne Plus hinzu. Für unsere Zwecke ist der vorausgewählte Punkt „Visual Studio Build“ die korrekte Wahl:

Neue Build Definition

Auch die vorgeschlagenen Schritte können übernommen werden. Da eine SharePoint Solution gebaut und bereitgestellt werden soll, ist es nötig, Visual Studio anzuweisen eine WSP Datei zu paketieren. Hierfür muss im Schritt Visual Studio Build „/p:IsPackaging=true“ als MSBuild Argument übergeben werden:

Packaging Visual Studio Build

Insgesamt wird in diesem Build nun im ersten Schritt NuGet Packages der Projekte wiederhergestellt, anschließend die Lösung gebaut und in eine WSP Datei paketiert. In der Solution vorhandene Unit Tests werden ausgeführt, um einen fehlerhaften Versionsstand bereits an dieser Stelle aufzudecken und die Bereitstellung nicht zu beginnen.

Für unser Beispiel reicht diese Build Definition vollkommen aus. Es ist jedoch denkbar, hier beispielsweise eine SharePoint App Versionsnummer hochzuzählen, SSIS Pakete zu erstellen oder JavaScript Unit Tests mit Chutzpah auszuführen.

Automatisiertes Deployment

Nachdem der Build erfolgreich abgeschlossen wurde, ist nun das Ziel, die Ergebnisse des Build Vorgangs automatisiert auf einem Testsystem bereitzustellen. Hierfür bringen die Visual Studio Team Services das Release Management mit:

Gate4 Release Management

Ein Release besteht aus einer oder mehreren Umgebungen:

Gate4 Release Environments

Im vorherigen Bild ist zu sehen, dass in dem Beispiel-Release eine Build Umgebung sowie eine Test Umgebung zu finden ist. Die Ergebnisse des Build-Vorgangs werden auf der Build-Umgebung bereitgestellt, sobald der oben erstellte Build erfolgreich durchlaufen ist, auf der Testumgebung nach der erfolgreichen Bereitstellung auf der Build Umgebung.

Da ein Release immer stark von einem Projekt abhängig ist, gibt es hier kein allgemeingültiges Rezept. Im Allgemeinen besteht ein Release aus mehreren Kopiervorgängen sowie einigen Powershell Skripten für das Deployment. Im obigen Release werden beispielsweise zuerst die nötigen SharePoint WSP-Dateien und die Datenbank (DACPAC Datei) in ein Zielordner kopiert. Es ist möglich, die Dateien auf einen anderen Server als auf den Build Server zu kopieren. Die Dateien werden per PowerShell kopiert, bereitgestellt und anschließend ein Warm-Up des SharePoints durchgeführt.

Im letzten Schritt werden diverse UI Tests durchgeführt, um die Qualität und Fehlerfreiheit des Releases sicherzustellen.

PhantomJS und UI Tests

Wie in der Einleitung bereits erwähnt, nutzen wir PhantomJS, um die Browser UI Tests durchzuführen. Um die Tests gut in den Release zu integrieren, wird ein Unit Test mit Visual Studio erstellt, welcher PhantomJS aufruft und den Rückgabewert (Exitcode) prüft. Hierdurch werden die Ergebnisse der UI Tests im Test Explorer der Visual Studio Team Services angezeigt. Der C# Unit Test sieht dabei wie folgt aus:

/// <summary>
/// Runs a phantom test
/// </summary>
/// <param name="configFile">test config file</param>
public static void RunPhantomTest(string configFile)
{
    // Run Phantom
    string cookieFile = configFile.Replace(".js", "");
    cookieFile += ".cookie.txt";

    if (File.Exists(cookieFile))
    {
        File.Delete(cookieFile);
    }

    Process process = new Process();
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    startInfo.WorkingDirectory = Environment.CurrentDirectory;
    startInfo.FileName =  PhantomPath;
    startInfo.Arguments = "--cookies-file=\""  + cookieFile + "\" " + TestPath + " --conf=\"" + configFile + "\"";
    process.StartInfo = startInfo;
    process.Start();

    bool exited = process.WaitForExit(Timeout);
    if(!exited)
    {
        try
        {
            process.Kill();
        }
        catch(Exception)
        {
        }
        Assert.Fail("Timeout in test.");
    }

    int exitCode = process.ExitCode;

    if (File.Exists(cookieFile))
    {
        File.Delete(cookieFile);
    }

    // Check Exit Code
    if(exitCode != 0)
    {
        ThrowTestFailException(exitCode, configFile);
    }
}

Hier wird PhantomJS mit einer Testkonfigurationsdatei gestartet. Dabei wird für jeden Test eine eigene Cookie Datei verwendet, um Seiteneffekte zu vermeiden. Auch wird als Sicherheitsmechanismus geprüft, ob der Test in ein Timeout läuft.

Nachdem PhantomJS durchgelaufen ist, wird der Exitcode geprüft, um eine detaillierte Fehlermeldung zurückzugeben, falls der Exitcode einen Fehler anzeigt. Hierfür wird die Testkonfigurationsdatei ausgelesen. Eine solche Testkonfigurationsdatei sieht in unserer Fehlerprüfung wie folgt aus:

"use strict";

module.exports = {
    bugbear: {
        browser: {
            screenSize: { width: 1600, height: 1200 },
            userAgent: "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
            acceptLanguage: "de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4",
            acceptEncoding: "identity"
        },
        siteCollectionUrl: "https://sampleSharePointSite/sites/TestSite",
        url: "#/addproject",
        resourceTimeout: 460000,
        log: 0,
        username: "testuser",
        password: "userpassword",
        verbose: 1,
        render: 1,
        applyIsLoaded: "",
        tests: [
            { "name": "Runtime Error on page", "type": "findText", "value": "Runtime Error", "successWhen": false, "failwhen": true, "exitcode": 10 },
            { "name": "Correlation ID on page", "type": "findText", "value": "something went wrong", "successWhen": false, "failwhen": true, "exitcode": 20 },

            { "name": "Project on page", "type": "findText", "value": "Project", "successWhen": true, "failwhen": true, "exitcode": 30 },
            { "name": "Project owner on page", "type": "findText", "value": "Project Owner", "successWhen": true, "failwhen": true, "exitcode": 40 },
            { "name": "Status on page", "type": "findText", "value": "Status", "successWhen": true, "failwhen": true, "exitcode": 50 },
            { "name": "Save Button on page", "type": "findId", "value": "g4SaveButton", "successWhen": true, "failwhen": true, "exitcode": 60 }
        ],
        includeJS: [
            { 'url': phantom.libraryPath + '/common/spfix.js', "state": "onInitialized" }
        ]
    }
};

Durch die Browser Konfiguration können benötigte Headerdaten gesetzt werden, sowie verschiedene Auflösungen simuliert werden. Anschließend wird die Seite getestet. Da es sich in diesem Beispiel um eine OnePage-App mit AngularJS handelt, wird eine weitere URL angegeben. Diese URL navigiert zu der eigentlichen Seite, nachdem der Nutzer erfolgreich eingeloggt wurde. Über den includeJS-Abschnitt können während der Testdurchführung zusätzliche JavaScript Dateien in jede Seite eingefügt werden. Diese spfix.js beinhaltet unter anderem die MicrosoftAjax.js, welche den Browser um die von SharePoint benutzen AJAX-Funktionalitäten erweitert. Zu finden ist diese Bibliothek unter: /_layouts/15/MicrosoftAjax.js

Unterhalb von dem Abschnitt tests werden die eigentlichen Testfälle konfiguriert. Das ist an dieser Stelle relativ einfach gehalten, da lediglich nach Text auf der Seite gesucht wird oder nach einem Element mit einer eineindeutigen ID. Der Vorteil dieser Konfigurationsdatei ist, dass neue UI Tests schnell definiert werden können. Zusätzlich können wir, wie oben erwähnt, diese Datei innerhalb von C# einlesen und anhand des Exitcodes den Namen des fehlgeschlagenen Tests als Exception auswerfen. Dadurch kann innerhalb der Visual Studio Team Services Oberfläche der genaue Fehler entnommen werden. So kann direkt anhand der Fehlermeldung die Ursache untersucht und der Fehler behoben werden.

Fazit

Durch Durchläufe derartiger UI Tests nach jedem Check-In, kann ein Fehler schnell sichtbar gemacht werden. Dadurch kann er einfach und kostengünstig behoben werden. Zusätzlich wird so die Qualität auf einem sehr hohen Niveau gehalten, da auch mögliche Seiteneffekte reduziert werden, weil die ganze Anwendung nach jeder Änderung vollautomatisch geprüft wird.



Diesen Blogeintrag bewerten:

2 Stimmen mit durchschnittlich 4/5 Punkten

Haben Sie Fragen zu diesem Artikel oder brauchen Sie Unterstützung?

Nehmen Sie mit uns Kontakt auf!

Wir unterstützen Sie gerne bei Ihren SharePoint-Vorhaben!


Schreibe einen Kommentar

Kontakt.
Lassen Sie sich von uns beraten
Wir freuen uns über Ihr Interesse an unseren Leistungen. Hinterlassen Sie
uns Ihren Namen, Ihre Telefonnummer und E-Mail Adresse – wir melden
uns schnellstmöglich bei Ihnen.
Kontakt aufnehmen