API Selenide: Desenvolvimento de testes funcionais em Java
Veja neste artigo como trabalhar com a API Selenide para o desenvolvimento de testes funcionais de aplicações web.
Atualmente o Selenium WebDriver é uma das ferramentas mais populares para o desenvolvimento de testes de funcionais de aplicações web, pois é fácil de usar e bastante flexível. No entanto, uma equipe de desenvolvimento web localizada na Estónia chamada Codeborne percebeu que ao usar o Selenium WebDriver teriam que escrever o mesmo código nos testes, por exemplo, tinham que inicializar e fechar o navegador a cada teste e outras duplicações desnecessárias. Assim, a equipe Codeborne desenvolveu uma API para retirar o código repetitivo, dando origem ao Selenide, que será o objeto de estudo desse artigo. Acompanharemos por essa introdução como essa API funciona para criar testes funcionais junto da linguagem Java.
Conhecendo o Selenide
O Selenide é uma API baseada no Selenium WebDriver para o desenvolvimento de testes funcionais web em Java, oferecendo uma ótima sintaxe para a escrita de testes, fácil de aprender e usar. A API resolve todos os problemas típicos, como testes de aplicações web modernas com Ajax e abstrai para o desenvolvedor o uso do WebDriver e as configurações do Selenium. Além disso, ele fornece métodos adicionais simples que o Selenium, por “default”, não oferece, como manipular radiobutton, drop-down, captura de tela e limpar o cache do navegador.
Nas próximas seções aprenderemos na prática sobre o Selenide e seus principais aspectos.
Criando e configurando o projeto
Para iniciarmos o desenvolvimento com Selenide utilizaremos o Eclipse, Maven e o JUnit. Para começar inicie o Eclipse e em seguida vá até File > New> Other ... e Maven > Maven Project. Clique em Next e na seguinte tela marque o checkbox Create a simple project e clique em Next novamente. Na janela que aparece, como na Figura 1, preencha os campos Group Id ", Artifact Id e em Packaging clique emwar.
Depois de criado o projeto precisamos fazer alguns ajustes: o primeiro deles é configurar o pom.xml do nosso projeto acrescentando o código da Listagem 1 entre as tags e no pom.xml.
<dependencies>
<!-- Selenide -->
<dependency>
<groupId>com.codeborne</groupId>
<artifactId>selenide</artifactId>
<version>2.23</version>
<scope>test</scope>
</dependency>
<!-- JUnit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Build deste projeto Maven -->
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<!-- Versão do plugin compiler do Maven -->
<version>3.3</version>
<configuration>
<!-- Versão do Java -->
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
Por fim, como o nosso projeto é uma aplicação web, precisamos gerar um arquivo de configuração chamado web.xml. Para isso vá até o o projeto maven e clique duas vezes. Em seguida clique com o botão direito no item “Deployment Descriptor: ” e logo depois clique em “Generate Deployment Descriptor Stub”. Selecione o projeto novamente e execute o Maven Update Project utilizando o Alt+F5 ou com o botão direito do mouse escolhendo a opção “Maven > Update Project”. Assim o nosso projeto já está configurado.
Trabalhando com seletores de elementos
Para o desenvolvimento de testes funcionais com Selenide precisamos entender como funciona a seleção de elementos (HTML) para que possamos realizar a automação de teste interagindo com esses elementos em uma interface web.
O Selenide fornece comandos simples e úteis para realizar esta tarefa. A seguir serão apresentados os comandos semelhantes à do jQuery para escolher os elementos (HTML) com Selenide:
- $(String seletorCss): Seleciona um elemento (HTML) pelo seu seletor marcado, por exemplo, o id. Assim, este comando retorna um objeto do tipo SelenideElement com referência a um elemento desejado;
- $(By): Semelhante ao comando anterior, com a diferença no modo em que passamos a instrução para escolher o elemento HTML utilizando um método static chamado By.
- $$(String seletorCss): Seleciona um elemento (html) pelo seu seletor CSS, por exemplo, o id. Este comando retorna um objeto do tipo ElementsCollection com referência a vários elementos (html);
- $$(By): Similar ao comando anterior, mas a diferença está apenas no modo em que passamos a instrução para escolher o elemento utilizando um método static chamado By.
E para trabalhar junto com os métodos anteriores o Selenide oferente métodos (static) utilitários que facilitam a seleção de elementos:
- byText: Buscar elemento (html) por texto;
- withText: Buscar elemento com determinado texto especificado;
- by: Buscar elemento pelo atributo;
- byTitle: Buscar elemento pelo atributo title;
- byValue: Buscar elemento pelo atributo value.
Faremos agora um exemplo prático utilizando os seletores de elementos do Selenide. Para isso, primeiramente vá ao diretório “ /src/main/webapp e nele crie um arquivo chamado seletores.html acrescentando o código da Listagem 2. É neste arquivo que conterá elementos HTML que serão úteis para os nossos testes com seletores do Selenide.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Trabalhando com seletores de elementos</title>
</head>
<body>
<div id="texto">Obter elemento com o id: texto</div>
<a title="Meu título">Obter elemento com o title: Meu título</a>
<form id="idFormulario">
<input name="nomeInput" type="text"
value="Obter elemento pelo atributo value" />
</form>
</body>
</html>
Em seguida, criaremos a nossa classe de testes que irá testar os elementos da listagem anterior. Para isso vá ao diretório /src/test/java e nele crie um pacote chamado “testes” e dentro deste crie uma classe chamada TesteSeletorElemento acrescentando o código da Listagem 3.
package testes;
import static com.codeborne.selenide.Selectors.*;
import static com.codeborne.selenide.Selenide.*;
import static org.junit.Assert.assertEquals;
import org.junit.*;
import org.openqa.selenium.By;
public class TesteSeletorElemento {
@Before
public void abreAPaginaParaTeste() {
open("http://localhost:8080/aprendendo-selenide/seletores.html");
}
@Test
public void testeSeletorElementoSelenideElement() {
assertEquals("<div id=\"texto\">Obter elemento com o id:
texto</div>", $(By.id("texto")).toString());
assertEquals("<input name=\"nomeInput\" type=\"text\"
value=\"Obter elemento pelo atributo value\"></input>",
$(By.name("nomeInput")).toString());
assertEquals("<div id=\"texto\">Obter elemento com o
id: texto</div>", $("#texto").toString());
assertEquals("<div id=\"texto\">Obter elemento com o
id: texto</div>", $(byText("Obter elemento com o id: texto")).toString());
assertEquals("<div id=\"texto\">Obter elemento com o
id: texto</div>", $(withText("Obter elemento com o id: texto")).toString());
assertEquals("<div id=\"texto\">Obter elemento com o
id: texto</div>", $(by("id", "texto")).toString());
assertEquals("<input name=\"nomeInput\" type=\"text\"
value=\"Obter elemento pelo atributo value\"></input>",
$(by("value", "Obter elemento pelo atributo value")).toString());
assertEquals("<a title=\"Meu título\"
>Obter elemento com o title: Meu título</a>",
$(by("title", "Meu título")).toString());
assertEquals("<a title=\"Meu título >Obter elemento com o title: Meu título</a>",
$(byTitle("Meu título")).toString());
assertEquals("<input name=\"nomeInput\" type=\"text\"
value=\"Obter elemento pelo atributo value\"></input>",
$(byValue("Obter elemento pelo atributo value")).toString());
}
@Test
public void testeSeletorElementosElementsCollection() {
assertEquals("[\n <form id=\"idFormulario\"></form>\n]",
$(By.id("idFormulario")).toString());
assertEquals("[\n <form id=\"idFormulario\"></form>\n]",
$(by("id", "idFormulario")).toString());
}
}
Observe que nossa classe de teste possui dois testes contendo afirmações que irão comparar se os elementos esperados são iguais aos elementos da Listagem 2 com o auxílio dos seletores do Selenide. É um exemplo simples apenas para fixar o uso dos seletores que iremos utilizar em exemplos concretos ou do mundo real ainda neste artigo. Para executar o nosso primeiro teste, antes teremos que publicar nossa aplicação tornando acessível para o Selenide, utilizando para isso o Tomcat 8.
Realizado o deploy da aplicação iremos agora executar os nossos testes, para isso selecione a classe de teste TesteSeletorElemento e depois clique com o botão direito do mouse para a opção “Run As > JUnit Test”. Por padrão, o Selenide irá executar os testes funcionais no navegador Firefox.
Se tudo ocorreu como esperado teremos o resultado semelhante à Figura 2.
Trabalhando com SelenideElement
A interface SelenideElement nada mais é do que um wrapper do Selenium WebDriver que o Selenide aprimorou trazendo para sua API e que agora fornece métodos adicionais facilitando o trabalho do engenheiro de teste no desenvolvimento de testes funcionais automatizados. A seguir serão apresentados alguns dos principais métodos adicionais dessa interface:
- should(Condição): Verifica se um determinado elemento atende a todas as condições dadas;
- shouldNot(Condição): Verifica se um determinado elemento não atende a todas as condições dadas;
- setValue(String): Define um valor no atributo value de algum elemento HTML;
- val(): Obtém o valor do atributo value de algum elemento HTML;
- pressEnter(): Pressiona o enter;
- isDisplayed(): Retorna um boolean da verificação se algum elemento é visível;
- exists(): Retorna um boolean da verificação se algum elemento existe;
- selectOptionByValue(String value): Seleciona a opção pelo valor do elemento;
- getSelectedOption(): Retorna a opção selecionada do elemento;
- getSelectedValue(): Retorna o valor da opção.
Agora faremos um exemplo utilizando os métodos adicionais do Selenide apresentados anteriormente. Para isso, no diretório /src/main/webapp crie um arquivo chamado selenideElement.html acrescentando o código da Listagem 4. É neste arquivo que conterá um formulário HTML que será útil para os nossos testes com métodos adicionais do Selenide.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Trabalhando com SelenideElement</title>
</head>
<body>
<form id="formulario">
<fieldset>
<legend>Trabalhe Conosco</legend>
<label for="input-1">Nome:</label>
<input type="text" placeholder="Informe seu nome" name="nome" /> <br>
<label>Sexo:</label>
<input type="radio" name="sexo" value="Masculino">Masculino
<input type="radio" name="sexo" value="Feminino">Feminino<br>
<label >Idioma:</label>
<input type="checkbox" name="idioma" value="Inglês">Inglês
<input type="checkbox" name="idioma" value="Espanhol">Espanhol<br>
<label>Vaga:</label>
<select id="vaga">
<option value="Desenvolvedor">Desenvolvedor</option>
<option value="Gerente de TI">Gerente de TI</option>
<option value="Suporte de TI">Suporte de TI</option>
</select> <br>
<input type="submit" value="Enviar" id="btnEnviar" /> <input
type="submit" value="Cancelar"
id="btnCancelar" />
</fieldset>
</form>
</body>
</html>
Na sequência criaremos uma classe de testes que irá testar os elementos da listagem anterior. Para isso no diretório “ /src/test/java crie uma classe chamada TesteSelenideElement acrescentando o código da Listagem 5.
package testes;
import static com.codeborne.selenide.Condition.visible;
import static com.codeborne.selenide.Selectors.by;
import static com.codeborne.selenide.Selenide.*;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
public class TesteSelenideElement {
@Before
public void abreAPaginaParaTeste() {
open("http://localhost:8080/aprendendo-selenide/selenideElement.html");
}
@Test
public void teste() {
$("#btnEnviar").should(visible);
$("#btnCancelar").shouldNot(visible);
$(By.name("nome")).setValue("Brendo Felipe");
selectRadio(By.name("sexo"), "Masculino");
$(by("value", "Inglês")).click();
$(By.id("vaga")).selectOptionByValue("Suporte de TI");
assertEquals("Brendo Felipe", $(By.name("nome")).val());
assertEquals(true, $("#btnEnviar").exists());
assertEquals(false, $("#btnCancelar").isDisplayed());
assertEquals("Masculino", getSelectedRadio(By.name("sexo")).val());
assertEquals("Inglês", $(By.name("idioma")).val());
assertEquals("Suporte de TI", $(By.id("vaga")).getSelectedValue());
$("#btnEnviar").pressEnter();
}
}
Note que no código escrevemos um teste que realiza o preenchimento de um formulário e isso verifica aspectos dos campos utilizando os métodos adicionais do Selenide. Após publicada novamente a nossa aplicação web com a Listagem 4 iremos executar os nossos testes. Para isso selecione a classe de teste TesteSelenideElement e depois clique com o botão direito na opção Run As > JUnit Test.
Se tudo ocorreu como esperado teremos o resultado igual à Figura 3.
Trabalhando com Condições
Atualmente muitas aplicações web usam AJAX para mudar partes do site de forma dinâmica, assim quando escrevemos testes funcionais com este efeito precisamos definir o tempo de espera até que o elemento desejado apareça. Para isso, o Selenide fornece uma classe chamada Condition que , ao contrário de Selenium WebDriver, o Selenide aguarda por algum tempo limite pré-definido.
Por padrão, o tempo limite do Selenide para aguardar é de quatro segundos, mas pode ser configurado via propriedade selenide.timeout. Além disso, a classe Condition também é usada para testar uma página verificando o estado em que estão os elementos HTML, por exemplo, verificar se input x está visível ou não, e outras verificações. Vejamos alguns atributos e métodos principais da classe Condition:
- visible | appear: Condição que indica que o elemento HTML é visível na página web;
- present | exist: Condição que indica que o elemento HTML existe na página web;
- hidden | disappear | not(visible): Condição que indica que o elemento HTML não é visível na página web;
- readonly: Condição que indica que o elemento HTML permite somente a leitura na página web;
- attribute: Condição que indica que algum atributo está presente em um elemento HTML;
- name: Condição que indica que o elemento HTML possui um determinado valor de name;
- value: Condição que indica que o elemento HTML possui um determinado valor de value;
- type: Condição que indica que o elemento HTML possui um determinado valor de type;
- id: Condição que indica que o elemento HTML possui um determinado valor de id;
- empty: Condição que indica que o elemento HTML está vazio;
- cssClass: Condição que indica que o elemento HTML possui um determinado valor de classe;
- focused: Condição que indica que o elemento HTML está em foco;
- enabled: Condição que indica que o elemento HTML está habilitado;
- disabled: Condição que indica que o elemento HTML está desabilitado;
- selected: Condição que indica que o elemento HTML está selecionado;
- text: Condição que indica que o elemento HTML possui um determinado valor ou texto sem levar em consideração letras maiúsculas e minúsculas;
- textCaseSensitive: Condição que indica que o elemento HTML possui um determinado valor ou texto considerando letras maiúsculas e minúsculas.
Faremos agora um exemplo prático utilizando a classe Condition com seus métodos e atributos apresentados anteriormente. Para isso, primeiramente no diretório /src/main/webapp crie um arquivo chamado condition.html acrescentando o código da Listagem 6. É neste arquivo onde conterá elementos HTML que serão úteis para os nossos testes.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Trabalhando com Condições</title>
</head>
<body>
<form id="meuFormulario">
<label for="nome" >Nome:</label>
<input type="text" id="nome" value="Brendão" readonly="readonly"
name="nome"><br/>
<label for="email" >Email:</label>
<input type="email" autofocus="autofocus" id="email" >
</form>
<div class="estilo_rodape" id="rodape"></div>
<p id="meuParagrafo">Meu texto</p>
</body>
</html>
Em seguida criaremos a nossa classe de testes que irá testar os elementos da Listagem 6. Para isso, no diretório “ /src/test/java crie uma classe chamada TesteCondition acrescentando o código da Listagem 7.
package testes;
import static com.codeborne.selenide.Condition.*;
import static com.codeborne.selenide.Selenide.*;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
public class TesteCondition {
@Before
public void abreAPaginaParaTeste() {
open("http://localhost:8080/aprendendo-selenide/condition.html");
}
@Test
public void testeConditionFormulario(){
$(By.id("meuFormulario")).should(visible);
$(By.id("meuFormulario")).should(exist);
$(By.id("meuFormulario")).shouldNot(hidden);
$(By.id("nome")).should(readonly);
$(By.id("nome")).should(attribute("value"));
$(By.id("nome")).should(name("nome"));
$(By.id("nome")).should(value("Brendão"));
$(By.id("nome")).should(type("text"));
$(By.id("nome")).should(id("nome"));
$(By.id("rodape")).should(empty);
$(By.id("rodape")).should(cssClass("estilo_rodape"));
$(By.id("email")).should(focused);
$(By.id("email")).should(enabled);
$(By.id("email")).shouldNot(disabled);
$(By.id("meuParagrafo")).should(textCaseSensitive("Meu texto"));
}
}
Note que no código escrevemos um teste que irá realizar a verificação ou checagem em determinados elementos HTML utilizando a classe Condition do Selenide.
Observe um trecho de código retirado da Listagem 7:
$(By.id("nome")).should(name("nome"))
Estamos fazendo uma verificação em um elemento HTML que tem o id=”nome” testando se o mesmo possui um atributo name com o valor nome: se sim o teste passa, senão o teste falha.
Não deixe de fazer o deploy da aplicação com o novo código conforme a Listagem 6.
Iremos agora executar o nosso teste e para isso escolheremos a classe de teste TesteCondition. Depois clique com o botão direito do mouse na opção Run As > JUnit Test e se tudo ocorreu como esperado teremos o resultado igual à Figura 4.
Trabalhando com Coleção de Elementos
Uma página HTML é constituída por vários elementos, como tabelas com várias linhas, múltiplas opções para um elemento selecionado, grupos de radiobuttons, diferentes tipos de listas, dentre outros. Então, para o desenvolvimento de testes funcionais vamos precisar de uma construção que nos permita executar operações em vários elementos e o Selenide fornece maneiras úteis para trabalhar com coleções de elementos, como é a chamada a classe ElementsCollection. A seguir serão apresentados os métodos que esta classe oferece para trabalhar:
- shouldBe: Verifica o que o elemento HTML tem em determinada condição;
- shouldHave: Verifica o que o elemento html deve ter em determinada condição;
- find: Busca alguma informação no elemento;
- filter: Filtra alguma informação no elemento;
- exclude: Filtra todos os elementos menos determinados elementos de um condição.
Na Listagem 8 temos um exemplo utilizando os métodos da classe ElementsCollection apresentados. Para isso, no diretório /src/main/webapp crie um arquivo chamado elementsCollection.html adicionando o código apresentado a seguir, pois é neste arquivo que conterá uma tabela HTML útil para os nossos testes.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Trabalhando com Coleção de Elementos</title>
</head>
<body>
<table border="1" id="tblGastosMensais" >
<caption>Gastos mensais</caption>
<tr>
<th>Mês</th>
<th>Gasto (R$)</th>
</tr>
<tr>
<td>Janeiro</td>
<td>R$250</td>
</tr>
<tr>
<td>Fevereiro</td>
<td>R$500</td>
</tr>
</table>
</body>
</html>
Na sequência criaremos uma classe de teste que irá testar os elementos da listagem anterior. Para isso, no diretório /src/test/java crie uma classe chamada TesteElementsCollection acrescentando o código da Listagem 9.
package testes;
import static com.codeborne.selenide.CollectionCondition.size;
import static com.codeborne.selenide.Condition.text;
import static com.codeborne.selenide.Selenide.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
public class TesteElementsCollection {
@Before
public void abreAPaginaParaTeste() {
open("http://localhost:8080/aprendendo-selenide/elementsCollection.html");
}
@Test
public void testeTabelaGastosMensais() {
$("#tblGastosMensais tr").shouldHave(size(3));
assertEquals(true, $("#tblGastosMensais tr td").findBy(text("R$500")).exists());
assertEquals(false, $("#tblGastosMensais tr td").filterBy(text("Janeiro")).isEmpty());
assertEquals(false, $("#tblGastosMensais tr td").excludeWith(text("Fevereiro")).isEmpty());
}
}
Note que na classe apresentada escrevemos um teste que irá verificar alguns aspectos dos elementos HTML de uma tabela com o auxílio da classe ElementsCollection. Observe o seguinte trecho de código retirado da listagem anterior:
$("#tblGastosMensais tr").shouldHave(size(3))
Com este código verificamos se o elemento #tblGastosMensais tr tem a quantidade de linhas tr igual a três: se sim o teste passa, senão o teste falha.
Após realizado o deploy da aplicação com o novo código da Listagem 8 iremos executar os nossos testes. Para isso, na classe de teste TesteElementsCollection clique com o botão direito selecionando a opção Run As > JUnitTest. Se tudo ocorreu como esperado teremos o resultado igual à Figura 5.
Trabalhando com ScreenShooter
Sabemos que durante a execução dos testes poderão ocorrer falhas e quando ocorrem gostaríamos de ter o máximo de informações para encontrar o mais rápido possível a razão da falha na aplicação. Com isso, o Selenide nos dá uma ajuda realizando um ScreenShooter da janela do navegador em caso de falha durante os testes. Além disso ele captura a página HTML, facilitando a depuração.
Para trabalhar com ScreenShooter do Selenide vamos automatizar um teste web que consiste em efetuar uma busca no Google e, a partir desse resultado, verificar se um determinado texto existe na primeira página. Contudo, para que o Selenide execute o ScreenShooter da página precisamos forçar a falha do teste.
Para criarmos este teste primeiro escolha o diretório “ /src/test/java e nele crie uma classe chamada TestePaginaBuscaNoGoogle adicionando o código da Listagem 10.
package testes;
import static com.codeborne.selenide.CollectionCondition.texts;
import static com.codeborne.selenide.Selenide.*;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import com.codeborne.selenide.junit.ScreenShooter;
public class TestePaginaBuscaNoGoogle {
@Rule
public final ScreenShooter makeScreenshotOnFailure = ScreenShooter.failedTests();
@Before
public void abreAPaginaParaTeste() {
open("https://www.google.com.br/");
}
@Test
public void testeScreenShooterComFalha() throws InterruptedException {
$("#lst-ib").val("Brendo Felipe").pressEnter();
$("#search").shouldHave(texts("Brendo Felipe | Facebook tal"));
}
}
Note que no código podemos destacar a seguinte instrução Java:
@Rule
public final ScreenShooter makeScreenshotOnFailure =
screenShooter.failedTests();
Com esta instrução dizemos que durante a execução dos testes, se algum teste encontrar falha, o Selenide imediatamente executa um ScreenShooter da página web contendo a falha detectada.
Agora iremos executar o teste com a classe TestePaginaBuscaNoGoogle e depois clicando com o botão direito do mouse na opção Run As > JUnit Test. Se tudo ocorreu como esperado teremos o resultado igual à Figura 6.
Com o resultado do teste forçando a falha, veremos agora o ScreenShooter do Selenide. Para isso atualize o projeto (apertando F5). Com isso, conseguimos visualizar o ScreenShooter gerado pelo Selenide que está presente no seguinte diretório: \build\reports\tests\testes\TestePaginaBuscaNoGoogle\testeScreenShooterComFalha.
Veja que o Selenide mostrou-se ser uma excelente ferramenta para automatizar testes funcionais em Java.
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Vídeo