Selenium ist als Testautomatisierungstool für Webanwendungen absoluter Standard. Der Standard WebDriver an sich hat keinen integrierten Reporter und das ist auch nicht seine Kernaufgabe. Diese wird vom WebDriver an die Testframeworks (JUnit / NUnit / MSTest / Jasmine usw.) delegiert. Es kann aber trotzdem vorkommen, dass die von den Testframeworks zur Verfügung gestellten Reporter für Auswertung von den Tests nicht ausreichend sind.

Gute Testreports haben allgemein folgende Vorteile:

  • Bieten gute Übersicht über den Testlauf auf verschiedenen Ebenen an: von hoch-granaular als Testmanagement Sicht bis feingranular für die Analyse einzelner Testschritte
  • Als lesbarer strukturierter Text / HTML abgelegt, enthalten fachliche Schritte
  • Enthalten eingebetete Screenshots, was beim Nachvollziehen der Probleme hilft
  • Vereinfachen die Fehlersuche
  • Können archiviert werden
  • Können von Menschen ohne Programmier-Kenntnissen ausgewertet werden

Auf dem Markt existieren viele mehr oder weniger gute Lösungen, die das Reporting für Selenium Tests bereitstellen. Nicht alle erfüllen die davor genannten Anforderungen an gute Testberichte, aber je nach Anwendungsfall und Projekt ist es auch oft gar nicht notwendig.

Bei uns in den Projekten hat sich der Testreporter ExtentReports bewährt. Neben einer kostenpflichtigen Version, gibt es auch eine Community Edition, die für den Einsatz in den meisten Projekten absolut ausreichend ist.

In diesem Beitrag möchte ich aufzeigen, wie ExtentReports in ein .NET Projekt eingebunden und benutzt werden kann.

Selenium Unit Test Projekt aufbauen

Visual Studio Projekt anlegen

Als erstes legen wir uns ein neues Testprojekt in Visual Studio an. Dazu verwenden wir hier das Standard MSTest Testprojekt von .Net Core

 

Die anschließend geöffnete .cs Datei sollte etwa so aussehen

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace SeleniumTests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
        }
    }
}

Selenium Webdriver & Nuget Pakete einbinden

Mit „Rechtsklick auf Projekt -> NuGet-Pakete verwalten… “ die NuGet Paketverwaltung öffnen

 

und nach „Selenium“ suchen.

 

Die beiden Pakete Selenium.WebDriver und Selenium.Chrome.WebDriver können installiert  und NuGet Package Manager vorerst geschlossen werden.

 

Ersten Selenium Test implementieren

Wir fügen unserem Selenium Test die erste Funktinalität hinzu, um zu prüfen, ob dieser mit den neuen NuGet Paketen einwandfrei funktioniert:

        [TestMethod]
        public void TestMethod1()
        {
            IWebDriver driver = new ChromeDriver(Environment.CurrentDirectory);
            driver.Navigate().GoToUrl("http://www.google.de");
            driver.FindElement(By.Name("q")).SendKeys("Hallo Test");
        }

Sobald dieser Test aus dem Test-Explorer gestartet wird, sollte unser erster Test erfolgreich durchlaufen:

 

 

ExtentReports Reporter nutzen

Reporter über NuGet Paket einbinden

Nun ist es Zeit den Reporter ExtentReports zu unserem Projekt hinzuzufügen. Dazu benötigen wir das entsprechende Nuget Paket.

Also öffnen wir wieder die NuGet Paketverwaltung und suchen nach ExtentReports:

ExtentReports Nuget Package hinzufügen

 

Wichtig:

Da wir hier ein .Net Core Testprojekt haben, ist es wichtig, den ExtentReports.Core zu verwenden. Bei einem klassischen .Net Framework Projekt (z.B. .Net Framework 4.6) kann  auch das erste nicht-core fähige ExtenReports Paket verwendet werden (siehe dazu den Beitrag auf Stackoverflow https://stackoverflow.com/questions/53816428/unable-to-generate-extentreport-for-netcore-app-2-1 ).

Nach der Installation kann der Reporter nun verwendet werden.

Reporter Umgebung konfigurieren

Damit der ExtenReports Reporter saubere Reports produziert, müssen wir diesen zuerst konfigurieren.

Dazu füge ich temporär folgenden Code direkt in die Unit Test Methode ein:

            //Report konfigurieren
            AventStack.ExtentReports.ExtentReports _extent = new AventStack.ExtentReports.ExtentReports();
            string folder = Path.Combine(Environment.CurrentDirectory, "report" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss"));
            var htmlReporter = new ExtentHtmlReporter(Path.Combine(folder, "SeleniumTestReport.html"));

            _extent.AddSystemInfo("Environment", "Testumgebung");
            _extent.AddSystemInfo("User Name", "Tester");
            _extent.AttachReporter(htmlReporter);

Mit diesem Code erstellen wir einen neuen _extent Reporter und weisen diesem einen HTML Reporter zu. Außerdem werden zwei System-Informationen hinzugefügt. Diese bestehen aus einem Key Value Paar und werden anschließend auf unserer Dashboard Seite dargestellt. Als Zielordner wird ein Ordner mit dem Namen „report<aktueller Zeitstempel>“ verwendet.

Testreporter konfigurieren und verwenden

Nachdem der eigentliche (globale) Report konfiguriert wurde, können einzelne TestReporter für jeden Testfall erstellt werden. Der Code dazu sieht auch sehr ähnlich aus:

            //TestReporter konfigurieren
            ExtentTest _testReporter = _extent.CreateTest("TestMethod1 Erster Selenium Test");
            _testReporter.Info("Starte Chrome Browser und öffne URL www.google.de");

Wie in dem Code zu sehen ist, wird zuerst für den Test ein neuer ExtentTest Reporter erstellt und anschließend sofort verwendet. Wir haben hier die Info Methode verwendet, aber wie in den meisten anderen Reportern stehen natürlich weitere Methoden für Error / Warning / Debug Protokollierung zur Verfügung.

 

 

Report schreiben

Da ExtentReports mit einer InMemory Datenbank arbeitet, muss am Ende noch die „Schreibeanweisung“ erfolgen, damit die erstellten Log Informationen in eine physikalische Report Datei weggesichert werden. Dazu wird die Methode _extent.Flush() aufgerufen.

Nun sollte der Gesamt-Testfall etwa so aussehen:

        [TestMethod]
        public void TestMethod1()
        {
            //Report konfigurieren
            AventStack.ExtentReports.ExtentReports _extent = new AventStack.ExtentReports.ExtentReports();
            string folder = Path.Combine(Environment.CurrentDirectory, "report" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss"));
            var htmlReporter = new ExtentHtmlReporter(Path.Combine(folder, "SeleniumTestReport.html"));

            _extent.AddSystemInfo("Environment", "Testumgebung");
            _extent.AddSystemInfo("User Name", "Tester");
            _extent.AttachReporter(htmlReporter);

            //Testreporter konfigurieren
            ExtentTest _testReporter = _extent.CreateTest("TestMethod1 Erster Selenium Test");
            _testReporter.Info("Starte Chrome Browser und öffne URL www.google.de");

            IWebDriver driver = new ChromeDriver(Environment.CurrentDirectory);
            driver.Navigate().GoToUrl("http://www.google.de");
            driver.FindElement(By.Name("q")).SendKeys("Hallo Test");

            _extent.Flush();
        }

 

Wird dieser ausgeführt, sollte in dem Testrun-Verzeichnis (Debug bzw. Release) ein neuer Ordner angelegt worden sein. In meinem Fall report2019-04-22-12-18-37, darin sind zwei Dateien zu finden:

  • dashboard.html – enthält eine high-level Übersicht über alle Testfälle des Testlaufs mit Charts und allgemeinen Informationen (wie z.B. von uns erstellten Systeminformationen)
  • index.html – enthält die Liste aller Testfälle in dem Report mit den dazugehörigen feingranularen Reporteinträgen

 Ausbau vom Reporter auf mehrere Tests

ExtentReports kann natürlich auch für das Reporting von Testläufen mit mehreren Testfällen verwendet werden. Dazu sind folgende Schritte notwendig:

  • Auslagern der ExtentReports Instanz in die statische
    [ClassInitialize] Methode
  • Auslagern der schreibenden Methode Flush in die statische [ClassCleanup] Methode
  • Auslagern des ExtentTest Reporters in [TestInitialize] Methode

Hier ist ein Beispiel wie ein Report mit zwei Testfällen erstellt werden kann:

 [TestClass] public class UnitTest1 { static AventStack.ExtentReports.ExtentReports _extent; static string folder; public TestContext TestContext { get; set; } private ExtentTest _testReporter; [ClassInitialize] public static void Initialize(TestContext context) { _extent = new AventStack.ExtentReports.ExtentReports(); folder = Path.Combine(Environment.CurrentDirectory, "reports" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss")); var htmlReporter = new ExtentHtmlReporter(Path.Combine(folder, "Automation_Report.html")); _extent.AddSystemInfo("Environment", "Testumgebung"); _extent.AddSystemInfo("User Name", "Tester"); _extent.AttachReporter(htmlReporter); } [ClassCleanup] public static void CleanUp() { _extent.Flush(); } [TestInitialize] public void TestInitialize() { _testReporter = _extent.CreateTest(TestContext.TestName); } [TestMethod] public void TestMethod1() { IWebDriver driver = new ChromeDriver(Environment.CurrentDirectory); driver.Navigate().GoToUrl("http://www.google.de"); _testReporter.Log(Status.Info, "TestMethod1 Erster Selenium Test"); driver.FindElement(By.Name("q")).SendKeys("Hallo Test"); _testReporter.Log(Status.Info, "Test ended"); _testReporter.Pass("Alles bestens!"); } [TestMethod] public void TestMethod2() { IWebDriver driver = new ChromeDriver(Environment.CurrentDirectory); driver.Navigate().GoToUrl("http://www.google.de"); _testReporter.Log(Status.Info, "Tippe ein in Google Suchfeld"); driver.FindElement(By.Name("q")).SendKeys("Hallo Welt"); try { //suche nach unbekanntem Element - hier provozieren wir einen Fehler driver.FindElement(By.Name("asdfasdf")).SendKeys("Hallo Welt"); } catch (Exception e) { _testReporter.Fail(e.Message); _testReporter.Debug(e.StackTrace); throw; } } } 

 

Anhängen von Screenshots an den Reporter

ExtentReports kann ebenfalls Screenshots an die Testschritte in Report hinzufügen, um die Fehleranalyse nachvollziehbarer und effizienter zu gestalten.

Dazu muss lediglich die Standard Screenshot Funktionalität von Selenium verwendet werden und anschließend CreateScreenCaptureFromPath() Methode aufgerufen werden.

Hier ist ein Beispiel, wie im Fehlerfall ein Screenshot geschossen werden kann:

 
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using System;
using System.IO;
using AventStack.ExtentReports;
using AventStack.ExtentReports.Reporter;
namespace SeleniumUnitTest
{
    [TestClass]
    public class UnitTest1
    {
        static AventStack.ExtentReports.ExtentReports _extent;
        static string folder;
        public TestContext TestContext { get; set; }
        private ExtentTest _testReporter;

        [ClassInitialize]
        public static void Initialize(TestContext context)
        {
            _extent = new AventStack.ExtentReports.ExtentReports();
            folder = Path.Combine(Environment.CurrentDirectory, "reports" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss"));
            var htmlReporter = new ExtentHtmlReporter(Path.Combine(folder, "Automation_Report.html"));
            _extent.AddSystemInfo("Environment", "Testumgebung");
            _extent.AddSystemInfo("User Name", "Tester");
            _extent.AttachReporter(htmlReporter); }

        [ClassCleanup]
        public static void CleanUp() { _extent.Flush(); }

        [TestInitialize]
        public void TestInitialize() { _testReporter = _extent.CreateTest(TestContext.TestName); }

		[TestMethod]
        public void TestMethod1()
        {
            IWebDriver driver = new ChromeDriver(Environment.CurrentDirectory);
            driver.Navigate().GoToUrl("http://www.google.de");
            _testReporter.Log(Status.Info, "TestMethod1 Erster Selenium Test");
            driver.FindElement(By.Name("q")).SendKeys("Hallo Test");
            _testReporter.Log(Status.Info, "Test ended"); _testReporter.Pass("Alles bestens!");
        }

        [TestMethod]
        public void TestMethod2()
        {
            IWebDriver driver = new ChromeDriver(Environment.CurrentDirectory);
            driver.Navigate().GoToUrl("http://www.google.de");
            _testReporter.Log(Status.Info, "Tippe ein in Google Suchfeld");
            driver.FindElement(By.Name("q")).SendKeys("Hallo Welt");

            try
            { //suche nach unbekanntem Element 
                driver.FindElement(By.Name("asdfasdf")).SendKeys("Hallo Welt");
            }
            catch (Exception e)
            {
                string path = CaptureScreenshot(driver);
                _testReporter.Fail(e.Message, MediaEntityBuilder.CreateScreenCaptureFromPath(path).Build());
                _testReporter.Log(Status.Debug, e.StackTrace);
                throw;
            }
        }

        public static string CaptureScreenshot(IWebDriver driver)
        {
            string localpath = ""; try
            {
                string name = "screenshot_" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss-fff");
                ITakesScreenshot ts = (ITakesScreenshot)driver; Screenshot screenshot = ts.GetScreenshot();
                localpath = Path.Combine(folder, name + ".png");
                screenshot.SaveAsFile(localpath, ScreenshotImageFormat.Png);
            }
            catch (Exception e) { throw (e); }
            return localpath;
        }
    }
}

So sollte nun der TestReport aussehen:

Html Reports in Selenium mit ExtentReports

 

 

Zusammenfassung

Nach nur wenigen Handgriffen konnten wir auf Schnelle eine komfortable Reporting Lösung zu unserem Selenium Test-Projekt hinzufügen. Mit dieser Lösung wird bei jedem Testlauf ein interaktiver Html-Report generiert, der uns eine übersichtliche Dashboard Seite anbietet. Von Dashboard aus kann man direkt zu einzelnen Testfällen navigieren und dort sowohl die Testdetails mit zugehörigen Schritten als auch eingebettete Screenshots kontextgenau sich anschauen.

Probiert es am besten gleich in Euren Projekten aus. Ich freue mich auf das Feedback, wie Ihr es einsetzt und ob diese Lösung für Eure Projekte hinreichend ist…

Waldemar Siebert on Linkedin
Waldemar Siebert
Begeisterter Berater, Schulungsleiter und Entwickler zu allem Themen rund um Softwarequalität und Testautomatisierung.

Mitgründer der Firma SimplyTest GmbH
0 Kommentare

Dein Kommentar

An Diskussion beteiligen?
Hinterlasse uns Deinen Kommentar!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.