Testando com Selenium/WebDriver e o Padrão de Objeto de Página

Testando com Selenium / WebDriver e o Padrão de Objeto de Página

1. Introdução

Neste artigo, vamos construir sobreprevious writeupe continuar a melhorar nossos testes Selenium / WebDriver, introduzindo o padrão de objeto de página.

2. Adicionando Selênio

Vamos adicionar uma nova dependência ao nosso projeto para escrever asserções mais simples e legíveis:


    org.hamcrest
    hamcrest-all
    1.3

A versão mais recente pode ser encontrada emMaven Central Repository.

2.1. Métodos adicionais

Na primeira parte da série, usamos alguns métodos de utilitário adicionais que usaremos aqui também.

Começaremos com o métodonavigateTo(String url) - que nos ajudará a navegar por diferentes páginas do aplicativo:

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

Então, oclickElement(WebElement element) - como o nome indica - se encarregará de executar a ação de clique em um elemento especificado:

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

3. Padrão de objeto de página

Selenium nos dá muitas APIs poderosas de baixo nível que podemos usar para interagir com a página HTML.

No entanto, à medida que a complexidade de nossos testes aumenta, a interação com os elementos brutos de baixo nível do DOM não é ideal. Nosso código será mais difícil de alterar, poderá ser interrompido após pequenas alterações na interface do usuário e, simplesmente, será menos flexível.

Em vez disso, podemos utilizar o encapsulamento simples e mover todos esses detalhes de baixo nível para um objeto de página.

Antes de começarmos a escrever nosso objeto de primeira página, é bom ter um entendimento claro do padrão - já que deve nos permitir emular a interação de um usuário com nosso aplicativo.

O objeto de página se comportará como um tipo de interface, que encapsulará os detalhes de nossas páginas ou elementos e exporá uma API de alto nível para interagir com esse elemento ou página.

Como tal, um detalhe importante é fornecer nomes descritivos para nossos métodos (por exemplo, clickButton(), navigateTo()), pois seria mais fácil para nós replicar uma ação realizada pelo usuário e geralmente levará a uma API melhor quando estivermos encadeando as etapas.

Ok, então agora, vamos em frente ecreate our page object - neste caso, nossa página inicial:

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;
    }
}

Observe como nossa implementação está lidando com os detalhes de baixo nível do DOM e expondo uma API agradável e de alto nível.

Por exemplo, a anotação@FindBy, nos permite preencher previamente nossoWebElements, isso também pode ser representado usando a APIBy:

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

Obviamente, ambos são válidos, no entanto, usar anotações é um pouco mais limpo.

Além disso, observe o encadeamento - nosso métodoclickOnStartHere() retorna um objetoStartHerePage - onde podemos continuar a interação:

public class StartHerePage {

    // Includes a SeleniumConfig attribute

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

    // constructor

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

Vamos escrever um teste rápido, em que simplesmente navegamos até a página e verificamos um dos elementos:

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

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

É importante levar em consideração que nossa homepage tem a responsabilidade de:

  1. Com base na configuração do navegador, navegue até a página.

  2. Uma vez lá, valide o conteúdo da página (neste caso, o título).

Nosso teste é muito direto; navegamos até a página inicial, executamos o clique no elemento "Start Here", que nos levará à página com o mesmo nome e, finalmente, apenas validamos que o título está presente.

Após a execução de nossos testes, o métodoclose() será executado e nosso navegador deve ser fechado automaticamente.

3.1. Separando Preocupações

Outra possibilidade que podemos levar em consideração é separar as preocupações (ainda mais), por ter duas classes distintas, uma cuidará de ter todos os atributos(WebElement ouBy) da nossa página:

public class exampleAboutPage {

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

O outro cuidará de ter toda a implementação da funcionalidade que queremos testar:

public class exampleAbout {

    private SeleniumConfig config;

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

    // navigate and getTitle methods
}

Se estivermos usando atributos comoBye não usarmos o recurso de anotação, é recomendado adicionar um construtor privado em nossa classe de página para evitar que seja instanciado.

É importante mencionar que precisamos passar a classe que contém as anotações, neste caso, a classeexampleAboutPage, em contraste com o que fizemos em nosso exemplo anterior, passando a palavra-chavethis.

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

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

Observe como agora podemos manter todos os detalhes internos da interação com nossa página na implementação e, aqui, podemos realmente usar esse cliente em um nível alto e legível.

4. Conclusão

Neste tutorial rápido, focamos em melhorar nosso uso deSelenium/WebDriver with the help of the Page-Object Pattern. Passamos por diferentes exemplos e implementações, para ver as maneiras práticas de utilizar o padrão para interagir com nosso site.

Como sempre, a implementação de todos esses exemplos e snippets pode ser encontradaover on GitHub. Este é um projeto baseado em Maven, portanto deve ser fácil importar e executar.