Pimp my testAUTOmation (Teil 3)

Ergebnisprotokolle und Reports

Mit Selenium lassen sich wie bei den meisten Testautomatisierungswerkzeugen Ergebnisprotokolle erzeugen. Diese maschinenlesbaren Dokumente in Formaten wie XML oder JSON sind nicht sehr benutzerfreundlich, aber sie können leicht in andere Werkzeuge eingebunden und damit lesbarer gemacht werden. Mit dieser Blogreihe möchte ich zeigen, wie sich mit einfachen Mitteln wichtige Funktionen in Selenium erweitern oder ausbauen lassen. Im ersten Teil habe ich vorgestellt, was Selenium 4 bringt und wie Screenshots eingesetzt werden können. Im zweiten Teil erstellten wir ein Video der Testdurchführung und im dritten Teil geht es um Reports. Dabei versuche ich die Ansätze nach ihrem Mehrwert (The Good) und ihren Herausforderungen (The Bad) zu bewerten und ggf. nützliche Hinweise (… and the Useful) zu geben.

Warum benötigen wir Reports?

Um die Frage nach dem “Warum“ zu beantworten, fange ich mit dem „schlimmsten“ Fall an: Die Auswertung und revisionssichere Ablage aller Testergebnisse ist in manchen Projekten verpflichtend vorgeschrieben, da hier gesetzliche oder andere Vorgaben eingehalten werden müssen. Bei Auftragsentwicklung kann das eine Forderung des Kunden sein. Bei Soft- und Hardwareentwicklung im Medizinbereich ist es eine Pflichtvorgabe für die Genehmigung und Zulassung durch die Behörden. Aber auch ohne diese Vorgaben bieten Reports und übersichtliche Protokolle einen Mehrwert für das Projekt. So lassen sich aus ihnen Kennzahlen und Trends ableiten, die das Team für seine Retrospektiven oder Weiterentwicklung benötigt.

Einfach mal ein Protokoll…

Es gibt viele Wege, einfache maschinenlesbare Testprotokolle zu erzeugen. Bei der Nutzung von automatisierten Tests (Selenium, JUnit) in Java-Projekten lässt sich über Maven das Plugin maven-surefire einbinden, welches während des Buildvorganges eine XML-Datei erzeugt, die die Ergebnisse eines Testlaufes aufzeichnet. Die XML-Datei beinhaltet den Namen der Testklasse und aller Testmethoden, die Gesamtdauer der Testdurchführung, die Dauer jedes Testfalles / jeder Testmethode sowie die Testergebnisse (tests, errors, skipped, failures).

… und was macht man damit.

Die maschinenlesbaren Protokolle werden meist automatisch im Buildwerkzeug erzeugt und in den Ergebnisbericht des Buildwerkzeuges eingebunden. So bindet Jenkins alle Ergebnisse der automatisierten Tests für Projekte ein, die mit Maven organisiert wurden. Darüber hinaus stehen in den meisten Buildwerkzeugen Plugins bereit, die die Testprotokolle einbinden oder sogar grafisch aufbereiten.

Die Projekte, die all ihre Testergebnisse dokumentieren müssen, stehen meist vor dem Problem, dass die Testergebnisse der verschiedenen Testarten (manuell, automatisiert etc.) in unterschiedlichen Werkzeugen erzeugt werden und damit in unterschiedlichen Formaten vorliegen. Darum bieten verschiedene Testmanagementwerkzeuge die Möglichkeit, die maschinenlesbaren Reports einzulesen. Damit stehen die Testergebnisse der automatisierten neben den manuellen Tests und können in einem Testbericht / Testreport zusammengefasst werden.

So lassen sich z. B. in dem Jira-Testmanagementplugin Xray die Testergebnisse für JUnit und NUnit manuell oder über eine Rest-API automatisch einlesen: https://confluence.xpand-it.com/display/public/XRAY/Import+Execution+Results.

Geht da noch mehr?

Sofern kein passendes Testmanagementwerkzeug vorhanden ist oder man eine Stand-alone-Variante benötigt, möchte ich noch das Werkzeug Allure Test Report vorstellen. Das Allure-Framework ist ein flexibles, leichtes und mehrsprachiges Testberichtstool mit der Möglichkeit, Screenshots, Protokolle usw. hinzuzufügen. Es bietet eine modulare Architektur und übersichtliche Webberichte mit der Möglichkeit, Anhänge, Schritte, Parameter und vieles mehr zu speichern. Dabei werden verschiedene Testframeworks unterstützt: JUnit4, JUnit5, Cucumber, JBehave, TestNG, …

Screenshot Allure Report

Um eine bessere Auswertung und Übersichtlichkeit in den Reports zu erzeugen, setzt das Allure-Framework eigene Annotations ein. Damit lassen sich die Ergebnisse der Testklassen und Testmethoden mit Features, Epics oder Stories verknüpfen. Über die Annotationen wie @Story, @Feature oder @Epic lassen sich zum Beispiel Testklassen oder Testmethoden mit den Anforderungen (Story, Epic, Feature) verknüpfen. Diese Verknüpfungen lassen sich dann in der Reportansicht auswerten und damit Aussagen zur Testabdeckung bzw. zum Projektfortschritt treffen.

Darüber hinaus lässt sich die Lesbarkeit der Testfälle durch die Annotation @Step und @Attachment verbessern. Wir können unseren Tesftfall (@Test) in einzelne Testmethoden aufteilen, um die Lesbarkeit und Wiederverwendbarkeit zu erhöhen. Mit der Annotation @Step des Allure-Frameworks lassen sich diese Testmethoden bzw. Testschritte im Testprotokoll anzeigen. Dabei unterstützt @Step die Anzeige einer Testschrittbeschreibung der verwendeten Parameter, die Schrittergebnisse sowie Attachments. Denn Testschritten lassen sich Texte in Form von String und Bilder in Form von byte[] anfügen. Siehe dazu das Codebeispiel …

Annotationen von Allure

@Feature("BMI Rechner - JUNIT")
public class TestAllureReport {
  
    @Test
    @Description("Aufruf des BMI-Rechners mit Testdaten für Untergwicht / Männer!")
    @Severity(SeverityLevel.CRITICAL)
    @Story("BMI Berechnung - Untergewicht für Männer")
    public void testUnderWeightMale() {
        inputTestdata("20", "200", "20", "Männlich");
        clickButtonCalc();
        compareResult("Untergewicht");
    }    
 
    @Step("EINGABE: Gewicht='{0}', Größe='{1}',Alter='{2}' und Geschlecht='{3}'")
    private void inputTestdata(String weight, String size, String age, String sex) {
        ...
    }
     
    @Step("Klick auf Berechnen")
    private void clickButtonCalc() {
        ...
    }
 
    @Step("Vergleiche, dass das Ergebnis auf '{0}' lautet")
    private void compareResult(String result) {
        ...
         
        // attach text
        attachment(str2);
         
        //make a screenshot and attach
        screenShot(driver, ".\\screenshots\\" ,"test_Oversized");
         
        ...
    }
    
 
    @Attachment(value = "String attachment", type = "text/plain")
    public String attachment(String text) {
        return "<p>" + text + "</p>";
    }
 
    @Attachment(value = "4", type = "image/png")
    private static byte[] screenShot(FirefoxDriver driver, String folder, String filename) {
 
        ...
         
        return new byte[0];
 
    }
     
}

… und das Ergebnis im Testprotokoll:

Screenshot Testprotokoll

Fazit

Mit Testprotokollen und Reports lassen sich sehr einfach automatisierte Testläufe erzeugen und in die eigene Toolkette einbinden. Dies ist zwar meist mit etwas Mehraufwand verbunden, aber dadurch werden Trends und Probleme schneller und besser erkannt.

Ergebnisprotokolle und Reports

The GoodThe Bad… and the Useful
• Visualisierung des aktuellen Status
• Es lassen sich Trends und Probleme erkennen

• Mehr Aufwand
• Neue Werkzeuge und Schnittstellen
• höhere Komplexität

• Allure Test Report → allure.qatools.ru/
• Xpand Xray → getxray.app/
• Plugins in Buildwerkzeugen

Pimp my testAUTOmation (Teil 2)

Videos der Testdurchführung aufnehmen

Mit dieser Blogreihe möchte ich zeigen, wie sich mit einfachen Mitteln wichtige Funktionen in Selenium einbauen lassen. Im ersten Teil habe ich vorgestellt, was Selenium 4 bringt und wie Screenshots eingesetzt werden können. Im zweiten Teil erstellen wir ein Video der Testdurchführung. Dabei versuche ich, die Ansätze nach ihrem Mehrwert (The Good) und ihren Herausforderungen (The Bad) zu bewerten und ggf. nützliche Hinweise (… and the Useful) zu geben.

Warum?

Aber zum Anfang stellen wir uns kurz die Frage: Warum ein Video bzw. einen Screencast der Testdurchführung aufzeichnen?

Mit einem Video haben wir eine Aufnahme des gesamten Testlaufs. Anders als mit einem Screenshot können wir so nicht nur das Testergebnis festhalten, sondern es lässt sich auch der Weg dorthin nachvollziehen.

Wie Screenshots können auch die Videos zum Debugging dienen und auf Probleme während des Testlaufes hinweisen. Darum ist es wie beim Screenshot sinnvoll, nur dann Videos zu erzeugen, wenn Probleme auftreten. Nach diesem Ansatz sollte die Video-Funktionalität um einen flexiblen und globalen Schalter erweitert werden, der sich je nach Notwendigkeit setzen lässt.

Aber die Videos können auch der Dokumentation der Testergebnisse dienen. In manchen Projekten ist eine ausführliche Dokumentation sogar verpflichtend vorgeschrieben, da hier gesetzliche oder andere Vorgaben eingehalten werden müssen.

Videos aufnehmen leicht gemacht

Da ich Selenium mit der Java-Ausprägung nutze, war mein erster Ansatz, Videos mit den „hauseigenen“ Funktionen von Java aufzunehmen bzw. ein passendes Framework zu nutzen. Meine erste Wahl fiel auf das Framework MonteCC, da sich hier mit der Hilfe von nur zwei Methoden der Bildschirm während der Testdurchführung aufnehmen ließ. In einer Methode vor dem Test wird die Videoaufnahme gestartet und in einer Methode nach dem Test wird die Aufnahme gestoppt und das Video im passenden Verzeichnis abgelegt.

private ScreenRecorder screenRecorder;
 
@BeforeEach
public void beforeTest() {
 
    GraphicsConfiguration gc = GraphicsEnvironment
            .getLocalGraphicsEnvironment()
            .getDefaultScreenDevice()
            .getDefaultConfiguration();
 
    try {
        this.screenRecorder = new ScreenRecorder(gc,
                new Format(MediaTypeKey, MediaType.FILE, MimeTypeKey, MIME_AVI),
                new Format(MediaTypeKey, MediaType.VIDEO, EncodingKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE,
                        CompressorNameKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE,
                        DepthKey, 24, FrameRateKey, Rational.valueOf(15),
                        QualityKey, 1.0f,
                        KeyFrameIntervalKey, 15 * 60),
                new Format(MediaTypeKey, MediaType.VIDEO, EncodingKey,"black",
                        FrameRateKey, Rational.valueOf(30)),
                null);
        this.screenRecorder.start();
 
    } catch (Exception e) {
        System.out.println("screenRecorder.start " + e.getMessage());
    }
}
 
@AfterEach
public void afterTest()  {
 
    try {
        this.screenRecorder.stop();
        List createdMovieFiles = screenRecorder.getCreatedMovieFiles();
        for (Object movie: createdMovieFiles) {
            File m = (File)movie;
            System.out.println("New movie created: " + m.getAbsolutePath());
        }
 
    } catch (IOException ioe) {
        System.out.println("screenRecorder.stop " + ioe.getMessage());
    }
}

Damit dies vor jedem Test passiert, nutzen wir die Annotations von JUnit:

@Test

Die Methode mit der Annotation @Test ist ein Testfall und wird bei der Testausführung gestartet und das Ergebnis im Testprotokoll erfasst.

@BeforeEach

Diese Methode wird vor jeder Testaufführung aufgerufen (siehe @Test).

@AfterEach

Diese Methode wird nach jeder Testaufführung aufgerufen (siehe @Test).

Wer eine komplette Aufzeichnung aller Testfälle benötigt, kann auch die Annotations @Before und @After nutzen, die vor allen bzw. nach allen Tests einer Testsuite (Testklasse) aufgerufen werden.

Große Nachteile von MonteCC sind, dass zum einen das letzte Release bereits mehr als sechs Jahre zurückliegt und zum anderen, dass die Videos im Format QuickTime vorliegen.

Als Alternative bot sich JavaCV (https://github.com/bytedeco/javacv) an. Die Bibliothek wird in GitHub fleißig gepflegt und speichert Videos im Format MPEG. Auch hier gibt es bei der Videoerzeugung zwei Methoden, die sowohl vor als auch nach dem Test aufgerufen werden können. Aber die JavaCV benötigt weitere Methoden, da parallel zum Testlauf in kurzen Abständen Screenshots erstellt und diese dann nach dem Test zu einem Video zusammenstellt werden. Eine ausführliche Anleitung findet ihr unter folgenden Link: https://cooltrickshome.blogspot.com/2016/12/create-your-own-free-screen-recorder.html.

Für den Einsatz beim automatisierten Testen habe ich folgende Änderungen vorgenommen:

/**
 *
 * https://github.com/bytedeco/javacv
 * https://cooltrickshome.blogspot.com/2016/12/create-your-own-free-screen-recorder.html
 */
public class RecordSeleniumJavaCV {
 
    // The WebDriver is a tool for writing automated tests of websites.
    FirefoxDriver driver;
 
    public static boolean videoComplete=false;
    public static String inputImageDir= "videos" + File.separator + "inputImgFolder"+File.separator;
    public static String inputImgExt="png";
    public static String outputVideoDir= "videos" + File.separator;
    public static String outputVideo;
    public static int counter=0;
    public static int imgProcessed=0;
    public static FFmpegFrameRecorder recorder=null;
    public static int videoWidth=1920;
    public static int videoHeight=1080;
    public static int videoFrameRate=3;
    public static int videoQuality=0; // 0 is the max quality
    public static int videoBitRate=9000;
    public static String videoFormat="mp4";
    public static int videoCodec=avcodec.AV_CODEC_ID_MPEG4;
    public static Thread t1=null;
    public static Thread t2=null;
    public static boolean isRegionSelected=false;
    public static int c1=0;
    public static int c2=0;
    public static int c3=0;
    public static int c4=0;
 
    /**
     * Explanation:
     * 1) videoComplete variables tells if user has stopped the recording or not.
     * 2) inputImageDir defines the input directory where screenshots will be stored which would be utilized by the video thread
     * 3) inputImgExt denotes the extension of the image taken for screenshot.
     * 4) outputVideo is the name of the recorded video file
     * 5) counter is used for numbering the screenshots when stored in input directory.
     * 6) recorder is used for starting and stopping the video recording
     * 7) videoWidth, videoFrameRate etc define output video param
     * 8) If user wants to record only a selected region then c1,c2,c3,c4 denotes the coordinate
     *
     * @return
     * @throws Exception
     */
    public static FFmpegFrameRecorder getRecorder() throws Exception
    {
        if(recorder!=null)
        {
            return recorder;
        }
        recorder = new FFmpegFrameRecorder(outputVideo,videoWidth,videoHeight);
        try
        {
            recorder.setFrameRate(videoFrameRate);
            recorder.setVideoCodec(videoCodec);
            recorder.setVideoBitrate(videoBitRate);
            recorder.setFormat(videoFormat);
            recorder.setVideoQuality(videoQuality); // maximum quality
            recorder.start();
        }
        catch(Exception e)
        {
            System.out.println("Exception while starting the recorder object "+e.getMessage());
            throw new Exception("Unable to start recorder");
        }
        return recorder;
    }
 
    /**
     * Explanation:
     * 1) This method is used to get the Recorder object.
     * 2) We create an object of FFmpegFrameRecorder named "Recorder" and then set all its video parameters.
     * 3) Lastly we start the recorder and then return the object.
     *
     * @return
     * @throws Exception
     */
    public static Robot getRobot() throws Exception
    {
        Robot r=null;
        try {
            r = new Robot();
            return r;
        } catch (AWTException e) {
            System.out.println("Issue while initiating Robot object "+e.getMessage());
            throw new Exception("Issue while initiating Robot object");
        }
    }
 
    /**
     * Explanation:
     * 1) Two threads are started in this module when user starts the recording
     * 2) First thread calls the takeScreenshot module which keeps on taking screenshot of user screen and saves them on local disk.
     * 3) Second thread calls the prepareVideo which monitors the screenshot created in step 2 and add them continuously on the video.
     *
     * @param r
     */
    public static void takeScreenshot(Robot r)
    {
        Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
        Rectangle rec=new Rectangle(size);
        if(isRegionSelected)
        {
            rec=new Rectangle(c1, c2, c3-c1, c4-c2);
        }
        while(!videoComplete)
        {
            counter++;
            BufferedImage img = r.createScreenCapture(rec);
            try {
                ImageIO.write(img, inputImgExt, new File(inputImageDir+counter+"."+inputImgExt));
            } catch (IOException e) {
                System.out.println("Got an issue while writing the screenshot to disk "+e.getMessage());
                counter--;
            }
        }
    }
 
    /**
     * Explanation:
     * 1) If user has selected a region for recording then we set the rectangle with the coordinate value of c1,c2,c3,c4. Otherwise we set the rectangle to be full screen
     * 2) Now we run a loop until videoComplete is false (remains false until user press stop recording.
     * 3) Now we capture the region and write the same to the input image directory.
     * 4) So when user starts the recording this method keeps on taking screenshot and saves them into disk.
     *
     */
    public static void prepareVideo()
    {
        File scanFolder=new File(inputImageDir);
        while(!videoComplete)
        {
            File[] inputFiles=scanFolder.listFiles();
            try {
                getRobot().delay(500);
            } catch (Exception e) {
            }
            //for(int i=0;i<scanFolder.list().length;i++)
            for(int i=0;i<inputFiles.length;i++)
            {
                //imgProcessed++;
                addImageToVideo(inputFiles[i].getAbsolutePath());
                //String imgToAdd=scanFolder.getAbsolutePath()+File.separator+imgProcessed+"."+inputImgExt;
                //addImageToVideo(imgToAdd);
                //new File(imgToAdd).delete();
                inputFiles[i].delete();
            }
        }
        File[] inputFiles=scanFolder.listFiles();
        for(int i=0;i<inputFiles.length;i++)
        {
            addImageToVideo(inputFiles[i].getAbsolutePath());
            inputFiles[i].delete();
        }
    }
 
    /**
     * Explanation:
     * 1) cvLoadImage is used to load the image passed as argument
     * 2) We call the convert method to convert the image to frame which could be used by the recorder
     * 3) We pass the frame obtained in step 2 and add the same in the recorder by calling the record method.
     *
     * @return
     */
    public static OpenCVFrameConverter.ToIplImage getFrameConverter()
    {
        OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();
        return grabberConverter;
    }
 
    /**
     * Explanation:
     * 1) We start a loop which will run until video complete is set true (done only when user press stop recording)
     * 2) We keep on monitoring the input  Image directory
     * 3) We traverse each file found in the input image directory and add those images to video using the addImageToVideo method. After the image has been added we delete the image
     * 4) Using the loop in step1 we keep on repeating step 2 and 3 so that each image gets added to video. We added a delay of 500ms so that this module does not picks a half created image from the takeScreenshot module
     * 5) When user press stop recording the loop gets broken. Now we finally traverse the input image directory and add the remaining images to video.
     *
     * @param imgPath
     */
    public static void addImageToVideo(String imgPath)
    {
        try {
            getRecorder().record(getFrameConverter().convert(cvLoadImage(imgPath)));
        } catch (Exception e) {
            System.out.println("Exception while adding image to video "+e.getMessage());
        }
    }
 
    /**
     * Explanation:
     * 1) We make a JFrame with the button for staring and stopping the recording. One more button is added for allowing user to record only a selected portion of screen
     * 2) If user clicks to select only certain region then we call a class CropRegion method getImage which helps in retrieving the coordinate of the region selected by user and update the same in variable c1,c2,c3,c4
     * 3) If user clicks on start recording then startRecording method is called
     * 4) If user clicks on stoprecording then stopRecording method is called
     */
    @BeforeEach
    public void beforeTest() {
 
        System.out.println("this.screenRecorder.start()");
 
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
        String timestamp  = dateFormat.format(new Date());
 
        outputVideo= outputVideoDir + "recording_" + timestamp + ".mp4";
 
        try {
            t1=new Thread()
            {
                public void run() {
                    try {
                        takeScreenshot(getRobot());
                    } catch (Exception e) {
                        System.out.println("Cannot make robot object, Exiting program "+e.getMessage());
                        System.exit(0);
                    }
                }
            };
            t2=new Thread()
            {
                public void run() {
                    prepareVideo();
                }
            };
            t1.start();
            t2.start();
            System.out.println("Started recording at "+new Date());
 
 
        } catch (Exception e) {
            System.out.println("screenRecorder.start " + e.getMessage());
        }
    }
 
    @AfterEach
    public void afterTest()  {
 
        System.out.println("this.screenRecorder.stop()");
 
        try {
            videoComplete=true;
            System.out.println("Stopping recording at "+new Date());
            t1.join();
            System.out.println("Screenshot thread complete");
            t2.join();
            System.out.println("Video maker thread complete");
            getRecorder().stop();
            System.out.println("Recording has been saved successfully at "+new File(outputVideo).getAbsolutePath());
 
        } catch (Exception e) {
            System.out.println("screenRecorder.stop " + e.getMessage());
        }
    }
 
    @Test
    public void testMe() {
         
        //toDo
 
    }
 
}

Gibt es einen Haken?

Somit haben wir nun mehrere Möglichkeiten, den automatischen Testlauf in einem Video festzuhalten, um bei Problemen diese nachvollziehen oder die Dokumentationspflichten erfüllen zu können.

Aber die Aufnahme während des Testdurchlaufes ist mit einem Risiko verbunden, dass der Tester / Testautomatisierer beachten sollte: Es ist ein Eingriff den normalen Testablauf, da wir ggf. die Timings der Geschwindigkeit ändern. Unser modifizierter Testlauf mit Videoaufnahme kann sich anders verhalten als ein Testlauf ohne Videoaufnahme.

Videos der Testdurchführung

The GoodThe Bad… and the Useful
• Aufnahme des gesamten Testlaufs
• Neben dem Testergebnis lässt sich auch der Weg dorthin nachvollziehen

• Es wird der Testlauf beeinflusst
• Verschiedene alte und kostenpflichtige Frameworks zur Videoaufnahme
• Codecs Probleme (nur QuicktimeView)
• JavaCV →
github.com/bytedeco/javacv




Pimp my testAUTOmation (Teil 1)

Selenium 4 & Screenshots

Softwareentwicklungsprojekte leben vom Einsatz moderner Testwerkzeuge, welche die Projektbeteiligten bei ihrer Arbeit unterstützen. Selenium gibt es seit dem Jahr 2004 und wirkt ggf. etwas angestaubt, aber trotzdem ist es nicht aus der Mode. Mit Selenium 4 holt es zu den neuen Herausfordern auf. Mit dieser Blogreihe möchte ich zeigen, was Selenium 4 bringt und wie sich mit einfachen Mitteln wichtige Funktionen einbauen lassen wie z. B. Screenshots, Videos, Reports und Ansätze von KI. Dabei versuche ich, die Ansätze nach ihrem Mehrwert (The Good) und ihren Herausforderungen (The Bad) zu bewerten sowie ggf. nützliche Hinweise (… and the Useful) zu geben.

Jason Huggins begann bereits 2004 mit der Arbeit an Selenium als internem Projekt zum Testen von Webseiten. Mit der Zeit entwickelte sich Selenium zum führenden Werkzeug in vielen Entwicklungsprojekten oder diente als Grundlage für andere Testwerkzeuge. Aktuell fühlt sich das Framework schon etwas altbacken an, aber es besticht gegenüber seinen Herausforderern mit einer breiten Unterstützung von Sprachen (Ruby, Java, Python, C#, JavaScript) und Browsern (Firefox, Internet Explorer, Safari, Opera, Chrome, Edge u. a.).

Was ist neu in Selenium 4?

Die Version 4, die für 2020 angekündigt ist, versucht, Selenium nun in die Moderne zu holen. Dazu gehören folgende Neuerungen:

WebDriver API wird W3C StandardDamit wird es nur noch einen WebDriver für alle Browser geben.
Selenium4 IDE TNG„TheNextGeneration“ Selenium IDE basiert auf Node JS und steht neben Firefox auch für Chrome bereit. Es lassen sich parallele Testläufe starten und es gibt erweiterte Testprotokollinformationen (Testergebnis, Laufzeit etc.).
Verbessertes WebDriver GridDas Einrichten sowie die Administration und der Docker-Support wurden verbessert.
AußerdemEs gibt eine bessere UI und das Reporting / Logging wurden optimiert.
DokumentationMit Version 4 soll es eine ausführliche Dokumentation und neue Tutorials geben.

Mit Version 4 setzt sich Selenium aus folgenden Teilen zusammen: dem Selenium WebDriver, der Selenium IDE und dem Selenium Grid. Der Selenium WebDriver ist eine Sammlung von verschiedenen Programmiersprachintegrationen, um Browser für eine Testautomatisierung anzusteuern. Die Selenium IDE ist ein Chrome oder Firefox Add-on, um direkt aus dem Browser mit der Testautomatisierung ohne Programmierkenntnisse zu starten und ermöglicht die Aufnahme und das Abspielen von Testfällen im Browser. Das Selenium Grid ermöglicht die gesteuerte und gleichzeitige Testdurchführung auf verschiedenen Maschinen und unterstützt die Administration unterschiedlicher Testumgebungen von einem zentralen Punkt aus. Damit lässt sich ein Testfall gegen verschiedene Browser- bzw. Betriebssystem-Kombinationen testen oder es lässt sich eine Liste von Testfällen skaliert auf mehreren Maschinen verteilt durchführen.

Selenium 4

The GoodThe Bad… and the Useful
WebDriver API → W3C Standardized
Selenium 4 IDE TNG
Improved WebDriver Grid
Documentation
New challenger like cypress etc.
Selenium 4 was announced for 2019

Latest Selenium 4 Alpha version 4.0.0-alpha-5


Screenshots können beim Testen helfen!

Neuere Frameworks zur Testautomatisierung besitzen bereits eine Funktion zur Erzeugung von Screenshots. Doch mit ein paar Codezeilen lässt sich auch in Seleniumtests die Möglichkeit für die Ablage von Screenshots einbauen.

private void screenShot(RemoteWebDriver driver, String folder, String filename) {
 
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
    String timestamp  = dateFormat.format(new Date());
 
    try {
        File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
        // Now you can do whatever you need to do with it, for example copy somewhere
        FileUtils.copyFile(scrFile, new File(folder + filename + "_" + timestamp + ".png"));
    }
    catch (IOException e) {
        System.out.println(e.getMessage());
    }
     
}

Dabei sollte man aber immer bei der Erzeugung und der Ablage der Datei auf den Einsatzzweck von Screenshots achten. Screenshots können zum einen dem Debugging dienen und auf Probleme hinweisen. Darum ist es sinnvoll, ggf. die Screenshots nur dann zu erzeugen, wenn Probleme auftreten. Nach diesem Ansatz kann man die Screenshot-Funktionalität um einen flexiblen und globalen Schalter erweitern, der sich je nach Notwendigkeit setzen lässt.

Zum anderen können Screenshots der Dokumentation der Testergebnisse dienen und in manchen Projekten sogar vorgeschrieben sein, da hier gesetzliche oder andere Vorgaben eingehalten werden müssen. Dann muss die Ablage der Screenshots nachvollziehbar sein und sich jede erzeugte Datei einen Testfall und dem zugehörigen Testlauf zuordnen lassen. Nach diesem Ansatz muss der Dateiname einen Verweis auf den Testfall und einen passenden Zeitstempel haben. Darüber hinaus muss auch das Ablageverzeichnis für diesen einen Testlauf erzeugt und benannt werden.

Screenshots

The GoodThe Bad… and the Useful
Ermöglicht den Nachweis des Ergebnisses des TestlaufsKann nur einen Moment darstellenKann auch zum „Debuggen“ genutzt werden

Im meinem nächsten Beitrag erstellen wir ein Video der Testdurchführung.