Test avec Selenium/WebDriver et le modèle d’objet de page

Test avec Selenium / WebDriver et le modèle d'objet de page

1. introduction

Dans cet article, nous allons nous appuyer sur lesprevious writeup et continuer à améliorer nos tests Selenium / WebDriver en introduisant le modèle d'objet de page.

2. Ajout de sélénium

Ajoutons une nouvelle dépendance à notre projet pour écrire des assertions plus simples et plus lisibles:


    org.hamcrest
    hamcrest-all
    1.3

La dernière version se trouve dans lesMaven Central Repository.

2.1. Méthodes supplémentaires

Dans la première partie de la série, nous avons utilisé quelques méthodes utilitaires supplémentaires que nous allons également utiliser ici.

Nous allons commencer par la méthodenavigateTo(String url) - qui nous aidera à naviguer à travers différentes pages de l'application:

public void navigateTo(String url) {
    driver.navigate().to(url);
}

Ensuite, leclickElement(WebElement element) - comme son nom l'indique - se chargera d'effectuer l'action de clic sur un élément spécifié:

public void clickElement(WebElement element) {
    element.click();
}

3. Modèle d'objet de page

Selenium nous offre de nombreuses API puissantes de bas niveau que nous pouvons utiliser pour interagir avec la page HTML.

Cependant, à mesure que la complexité de nos tests augmente, l'interaction avec les éléments bruts de base du DOM n'est pas idéale. Notre code sera plus difficile à modifier, risque de se briser après de petites modifications de l'interface utilisateur, et sera tout simplement moins flexible.

Au lieu de cela, nous pouvons utiliser une encapsulation simple et déplacer tous ces détails de bas niveau dans un objet de page.

Avant de commencer à écrire notre objet de première page, il est bon d'avoir une compréhension claire du modèle, car il devrait nous permettre d'émuler l'interaction d'un utilisateur avec notre application.

L'objet de page se comportera comme une sorte d'interface, qui encapsulera les détails de nos pages ou de nos éléments et exposera une API de haut niveau pour interagir avec cet élément ou cette page.

En tant que tel, un détail important est de fournir des noms descriptifs pour nos méthodes (ex. clickButton(), navigateTo()), car il serait plus facile pour nous de répliquer une action entreprise par l'utilisateur et conduira généralement à une meilleure API lorsque nous enchaînons les étapes ensemble.

Ok, alors maintenant, allons-y etcreate our page object - dans ce cas, notre page d'accueil:

public class exampleHomePage {

    private SeleniumConfig config;

    @FindBy(css=".header--menu > a")
    private WebElement title;

    @FindBy(css = ".menu-start-here > a")
    private WebElement startHere;

    // ...

    public StartHerePage clickOnStartHere() {
        config.clickElement(startHere);

        StartHerePage startHerePage = new StartHerePage(config);
        PageFactory.initElements(config.getDriver(), startHerePage);

        return startHerePage;
    }
}

Remarquez comment notre implémentation traite les détails de bas niveau du DOM et expose une belle API de haut niveau.

Par exemple, l'annotation@FindBy, nous permet de pré-remplir nosWebElements, cela peut également être représenté en utilisant l'APIBy:

private WebElement title = By.cssSelector(".header--menu > a");

Bien sûr, les deux sont valables, mais utiliser des annotations est un peu plus propre.

Notez également le chaînage - notre méthodeclickOnStartHere() renvoie un objetStartHerePage - où nous pouvons continuer l'interaction:

public class StartHerePage {

    // Includes a SeleniumConfig attribute

    @FindBy(css = ".page-title")
    private WebElement title;

    // constructor

    public String getPageTitle() {
        return title.getText();
    }
}

Faisons un test rapide, dans lequel nous naviguons simplement vers la page et vérifions l'un des éléments:

@Test
public void givenHomePage_whenNavigate_thenShouldBeInStartHere() {
    homePage.navigate();
    StartHerePage startHerePage = homePage.clickOnStartHere();

    assertThat(startHerePage.getPageTitle(), is("Start Here"));
}

Il est important de prendre en compte que notre page d’accueil a la responsabilité de:

  1. En fonction de la configuration du navigateur donnée, accédez à la page.

  2. Une fois là-bas, validez le contenu de la page (dans ce cas, le titre).

Notre test est très simple. nous naviguons vers la page d'accueil, exécutons le clic sur l'élément «Commencer ici», ce qui nous mènera à la page portant le même nom, et enfin, nous validerons simplement que le titre est présent.

Après l'exécution de nos tests, la méthodeclose() sera exécutée et notre navigateur devrait être fermé automatiquement.

3.1. Séparer les préoccupations

Une autre possibilité que nous pouvons prendre en considération pourrait être de séparer les préoccupations (encore plus), en ayant deux classes distinctes, on veillera à avoir tous les attributs(WebElement ouBy) de notre page:

public class exampleAboutPage {

    @FindBy(css = ".page-header > h1")
    public static WebElement title;
}

L'autre s'occupera de toute l'implémentation de la fonctionnalité que nous voulons tester:

public class exampleAbout {

    private SeleniumConfig config;

    public exampleAbout(SeleniumConfig config) {
        this.config = config;
        PageFactory.initElements(config.getDriver(), exampleAboutPage.class);
    }

    // navigate and getTitle methods
}

Si nous utilisons des attributs en tant queBy et n'utilisons pas la fonction d'annotation, il est recommandé d'ajouter un constructeur privé dans notre classe de page pour l'empêcher d'être instancié.

Il est important de mentionner que nous devons transmettre la classe qui contient les annotations dans ce cas la classeexampleAboutPage, contrairement à ce que nous avons fait dans notre exemple précédent en passant le mot-cléthis.

@Test
public void givenAboutPage_whenNavigate_thenTitleMatch() {
    about.navigateTo();

    assertThat(about.getPageTitle(), is("About example"));
}

Remarquez comment nous pouvons maintenant conserver tous les détails internes d'interaction avec notre page dans l'implémentation. Ici, nous pouvons réellement utiliser ce client à un niveau élevé et lisible.

4. Conclusion

Dans ce tutoriel rapide, nous nous sommes concentrés sur l'amélioration de notre utilisation deSelenium/WebDriver with the help of the Page-Object Pattern. Nous avons examiné différents exemples et mises en œuvre pour voir les moyens pratiques d'utiliser le modèle pour interagir avec notre site.

Comme toujours, l'implémentation de tous ces exemples et extraits de code peut être trouvéeover on GitHub. Ceci est un projet basé sur Maven, il devrait donc être facile à importer et à exécuter.