TestAutomatisering & PerformanceTesten

Cucumber, Selenium en het gebruik van het Page Object Pattern

Als je Selenium gebruikt om je testen aan te sturen, kan je gebruik maken van het Page Object Pattern om een laag van abstractie aan te maken: Het maakt een model van je pagina zodat het makkelijker is om acties op die pagina uit te voeren. Dit heeft grote voordelen: Zodra er een wijziging op de pagina plaatsvindt, hoef je alleen het model aan te passen en niet je test acties. Een tester kan daarnaast redelijk eenvoudig teststappen opbouwen zonder de achterliggende Selenium code te hoeven beheersen.

Het spreekt voor zich dat je het Page Object Pattern graag zou willen gebruiken als je wilt testen met het Cucumber framework: Je glue code (of steps) kunnen dan op een hoog abstractielaag gemaakt worden waardoor je het lostrekt van het onderliggende uitvoerende mechanisme.

Voor een enkele pagina kan je dat als volgt doen:

public class CustomerStep {
    // maak een page object aan voor de customer page
    static CustomerPage customerPage = new CustomerPage();

    @Given("^I navigate to the customers page$")
    public void I_navigate_to_the_customers_page() throws 
                                               Throwable {
        // roep deze methode aan op het page object
        customerPage.makeActivePage(); 
    }
}

public class CustomerPage {

    // laten we hier een webDriver aanmaken zodat we kunnen 
    // interacteren met de pagina.
    public WebDriver webDriver;

    public CustomerPage() {
        WebDriver webDriver = new FirefoxDriver();
    }

    public void makeActivePage() {
        webDriver.navigate().to("http://foo.com/customer.html");
    }
}

Nu hebben we een werkend geheel waarbij we het Page Object Pattern kunnen gebruiken binnen Cucumber. We krijgen alleen een probleem als we meerdere pagina’s gaan gebruiken. Voor elke pagina wordt er namelijk een nieuwe webdriver aangemaakt. Niet handig als je meerdere scenario’s op dezelfde context (dus in dezelfde browsersessie) uit wilt voeren.

Dat lossen we als volgt op: We maken een class aan met een static webdriver die overerfbaar is.

public class CommonPage {

    // De webDriver verplaatsen we hiernaartoe. We maken hem 
    // static zodat er maar 1 webdriver aangemaakt wordt, 
    // onafhankelijk van het aantal pagina instanties die er 
    // gebruikt worden.
    public static WebDriver webDriver;

    protected CommonPage() {
        if (webDriver == null)
            webDriver = new FirefoxDriver();
    }
}

Wanneer we een nieuw Page Object maken, dan overerven we van deze class. Op die manier maken we altijd gebruik van dezelfde webdriver. Hieronder zien we hoe de het CustomerPage object eruit ziet met een CommonPage als super class:

public class CustomerPage extends CommonPage {

    // We gebruiken de webDriver van de Super class
    public void makeActivePage() {
        webDriver.navigate().to("http://foo.com/customer.html");
    }
}

De class ziet er dus nog simpeler uit, terwijl we toch altijd gebruik kunnen maken van de webdriver.

Een ander voordeel is, is dat we generieke acties, die dus niet specifiek  tot een pagina behoren, kwijt kunnen in deze super class: Alle pagina objecten hebben vanaf dan toegang tot deze aspecifieke methodes.

public class CommonPage {

    // [ ... ]

    // Op alle pagina’s komen secties voor. Laten we hier een
    // herbruikbare methode van maken. Alle pagina objecten kunnen
    // nu gebruik maken van “getSections”
    public List<WebElement> getSections(String sectionName) {
        return webDriver.findElements(
            By.cssSelector("section." + sectionName));
    }
}

Nu is de method “getSections” te gebruiken door iedere PageStep library. Op deze manier kunnen we dus ook een Common PageStep library maken waar we alle Common Steps in plaatsen:

public class CommonSteps {

    // We gebruiken geen specifieke page om onze acties op te 
    // doen, we kunnen natuurlijk wel een common page object 
    // gebruiken.
    CommonPage commonPage = new CommonPage();

    @Before
    public void beforeScenario() {
        // Plaats hier acties die altijd moeten gebeuren voordat 
        // een scenario uitgevoerd moet worden.
        // Bedenk eens wat je hier allemaal zou kunnen doen!
    }

    // Een pagina aspecifieke actie. Die kunnen we het beste 
    // hier kwijt.
    @Then("^it contains a \"([^\"]*)\" section$")
    public void it_contains_a_section(String sectionName) throws 
                                                     Throwable {
        List<WebElement> sections = 
            commonPage.getSections(sectionName);
        assertTrue("a section "+sectionName+" could be found.", 
            !sections.isEmpty());
    }
}

Daarnaast hebben we meteen een mooie placeholder voor de acties die voor, met de @Before annotatie, en na, met behulp van de @After annotatie, een scenario moeten gebeuren.

Door slim gebruik te maken van pagina objecten, overerving en een static webdriver kan een net en overzichtelijke codebasis gemaakt worden voor Cucumber testen die gebruik maken van Selenium. We splitsen de stap op in een beoogde actie op de pagina door een call naar het pagina object en de specifiek invulling van de actie door Selenium. Ook splitsen we generieke acties van specifieke pagina acties door gebruik te maken van een common library.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Nieuws

Blijf op de hoogte

Workshop ‘Stop de Magie!’ bij Qquest

04/12/2018

In het kader van de 4e techday van Qquest heeft Chris met ondersteuning van HenkJaap een workshop gegeven. Basis was de presentatie en demo ‘No more magic’ van Bas en Chris, welke al een groot succes was op de TestAutomationDay en TestNet. Centraal bij het onderwerp ‘No more Magic’ staat het idee dat er bij […]

Visual Regression Testing – Wat is het en wat heb je eraan?

07/11/2018

Visual Regression Testing, of visuele regressie testen, is een categorie van testen die zich focust op het identificeren van visuele wijzigingen tussen iteraties of versies van een website. Dit kan handmatig door schermen of schermafdrukken te vergelijken, maar het is beter herhaalbaar en sneller te testen door dit automatisch te doen. Het mooiste is om deze testen als een […]

Meer efficiency en flexibiliteit in API’s

04/10/2018

Er wordt steeds meer gebruik gemaakt van GraphQL API. Tijdens mijn laatste opdracht heb ik hier dan ook mee gewerkt.. Graag deel ik mijn ervaringen hierover in een aantal blogs. In deze eerste blog wil ik het graag hebben over de uitdagingen met REST API en hoe GraphQL deze oplost. Maar eerst even een korte […]

Impact tooling op performance: Dynatrace

21/09/2018

In deze blog geef ik kort de resultaten weer van een onderzoekje dat ik bij één van mijn laatste opdrachten heb gedaan naar de impact van het gebruik van de tool Dynatrace op de infrastructuur waar het op draait. Mocht je gebruik maken van tooling als Dynatrace of op een andere manier geïnteresseerd zijn in […]

Tips en tricks voor Protractor

06/09/2018

Vanuit PerformanceArchitecten doen we graag aan kennisdeling. Van tool reviews tot aan complete best practices maar ook van een aantal simpele tips en tricks die je kan gebruiken in je dagelijkse werk. Vandaag in die laatste categorie voor gebruikers van Protractor: (Javascript) timing issues en het managen van de volgorde van uitvoeren van actions. Inleiding […]

PerformanceArchitecten @The Next Web conferentie

04/07/2018

Was het een interessante conferentie? Beslist. Heeft TNW PerformanceArchitecten op nieuwe ideeën gebracht? Zeker. Heb jij TNW gemist, maar wil je je wel in vijf minuten op de hoogte laten brengen? Lees dan snel verder! En mocht je er wel zijn geweest.. We zijn benieuwd naar jouw beeld! Wat is de Next Web? Voor hen […]

De ‘waar begin ik met testautomatisering’ handleiding.

11/04/2018

Wij worden regelmatig gevraagd te helpen bij het opzetten of verbeteren van testautomatisering in een Agile omgeving bij een klant. En hoeveel ervaring je ook hebt, wat je opdracht ook precies inhoudt en in welk team je ook terechtkomt, het is altijd even zoeken waar te beginnen. Onderstaand stappenplan ondersteunt hierbij. PerformanceArchitecten organiseert veel kennissessies. Zo […]

Wat is het Bug Filter?

26/03/2018

Een algemeen gedeelde opvatting over het doel van testen binnen software ontwikkeling is “het tegenhouden van bugs en het afdekken van risico’s”. Over hoe dit vervolgens het best valt te organiseren, bestaan er echter vaak veel meningsverschillen. In deze 2 minute snack sta ik graag even stil bij een inzicht dat verhelderend werkt in deze […]

Testen? Begin bij de basis! | Het belang van unittesten

19/02/2018

Inleiding Mijn vrouw en ik zijn op dit moment bezig met het bouwen van een huis. In dit geval niet als bouwvakker of aannemer, maar dan toch wel als opdrachtgever. Spannend vinden we het zeker, leuk ook. Wat heeft dit te maken met unittesten zou je denken. Nou, het volgende… Het huis wordt namelijk gebouwd […]

De Absolute Beginners Guide voor API Testen met rest-assured.io

16/01/2018

Omdat het moeilijk was om een eenvoudige tutorial te vinden voor rest-assured.io, ben ik na eerst zelf uit te vinden hoe het werkt, maar eens begonnen met een tutorial die de absolute basics uitlegt over rest-assured. In deze post laat ik zien hoe we op een zo eenvoudig mogelijke manier een API test kunnen maken met […]

APACHE MPM (op *nix servers)

07/11/2017

Benieuwd naar de impact van het wijzigen van Apache MPM Prefork naar Worker? Lees dan door! Bij één van onze klanten heb ik dit onderzocht. Omdat dit ook interessant kan zijn voor anderen, deel ik mijn resultaten en ervaringen graag. Het is misschien wat technisch allemaal, maar voor performancetesters, de doelgroep, is het vast goed […]

Performancetesten en CI/CD, gaat dat samen?

13/10/2017

De afgelopen najaarseditie van Testnet stond onder het thema Continuous Everything vooral stil bij CI/CD en natuurlijk testen. Gezien DevOps en CI/CD ook grote invloed hebben op het vakgebied performance (testen), zijn wij blij dat we vanuit PerformanceArchitecten een bijdrage mochten leveren door middel van het delen van onze visie hierop. Onze collega René Meijboom […]