Imagine uma aplicação web com cem testes funcionais automatizados e, ao fazermos uma alteração de funcionalidade desejamos executar os testes de regressão com o intuito de verificar se as outras não foram danificadas. Após a execução sem problemas, podemos verificar que o tempo gasto nestes foi algo em torno de seis horas. Diante disso, precisamos otimizar para reduzir o tempo de execução dos nossos testes funcionais automatizados.
Uma possível solução seria a distribuição da execução destes utilizando o Selenium GRID usando duas máquinas virtualizadas com o apoio do VirtualBox. Com essa distribuição de tarefas, o que levaria seis horas para rodar tudo passaria a gastar metade do tempo. Este artigo destaca essa solução na prática, mas com menos testes.
O Selenium WebDriver e o TestNG permitem escrever, executá-los e escolher em quais navegadores isso ocorrerá. Veremos nesse artigo como isso funciona na prática. Mas antes de iniciarmos o desenvolvimento, vamos conhecer melhor as ferramentas utilizadas.
Selenium WebDriver
É um framework de automação de testes, fornecendo uma API em diferentes linguagens, como Java, C#, Python e outros, que automatiza ações de usuário na interface web em diferentes navegadores. Ele serve para integrar o código-fonte com a tela do sistema e com o banco de dados. Sua arquitetura é apresentada na Figura 1.
Selenium Grid
Este permite distribuir os testes escritos com a API WebDriver em várias máquinas físicas ou virtuais. Além disso, o Selenium Grid tem dois conceitos importantes para o seu funcionamento:
- Hub: atua como um ponto central, ou seja, um servidor que carregará todos os testes a serem executados e distribuídos para o(s) Node(s). Recomenda-se criar apenas um único Hub para comandar;
- Node: atua como um ponto ligado ao Hub central esperando receber os testes a serem executados. Vários nodes podem ser ligados ao Hub central, mas nenhum pode se ligar a outro.
Vejamos na Figura 2 a arquitetura do Selenium Grid.
Para apoiar a qualidade do software, a família Selenium ainda conta com um IDE próprio para ajudar na execução de testes funcionais
Para esse artigo também usaremos, em conjunto com o IDE Eclipse :
- VirtualBox: É um software de virtualização de plataforma, que permite ao usuário instalar e executar sistemas operacionais independentes em um único computador.
- TestNG: É um framework de criação e execução de testes de unidade em Java;
- Apache Maven: É uma ferramenta de gestão de projetos de software que utiliza o conceito de POM (modelo de objeto de projeto) para a compilação de projetos que envolve a construção, elaboração de relatórios e documentação em uma central de informações, sendo compatível com diferentes linguagens. Mas usaremos a linguagem Java 8 para esse exemplo.
Visão geral
Desenvolveremos os testes funcionais distribuídos na aplicação web pronta que está em http://artigo.pe.hu.
Então o primeiro teste consiste em acessar na página inicial a opção “Trabalhe Conosco”, preencher todos os campos do formulário e enviá-lo. Ao final, verifica-se se o envio deu certo. O segundo consiste em entrar na página inicial e clicar na opção Conversor -> Temperatura e ao carregar a página devemos testar todas as combinações de cálculos de conversão de temperatura, verificando se todos os resultados estão corretos.
O primeiro teste será executado no Firefox da primeira máquina virtual (Ubuntu; Node 1) e o segundo no Google Chrome da segunda máquina virtual (Ubuntu; Node 2).
Para que tudo funcione seguiremos os passos a seguir:
- Configuração das máquinas i. Configuração do Hub central na nossa máquina física local utilizando o Selenium Grid;ii. Virtualização de duas máquinas com Ubuntu utilizando o VirtualBox;iii. Configuração dos Nodes nas duas máquinas virtuais, e após, ligá-las ao Hub central utilizando Selenium Grid;
- Criação de um novo projeto no Eclipse com Maven utilizando o Java 8;
- Criação das classes utilizando o Selenium WebDriver;
- Criação das classes de testes utilizando o TestNG e posterior execução dos mesmos;
Assim, a visão geral desse artigo pode ser vista na Figura 3.
Configuração das máquinas
Para começar precisamos baixar o Selenium Standalone Server .jar (vide seção Links). Para criar o hub central em nossa máquina física local executaremos o comando a seguir (use o shell ou prompt de comando, pois o comando funciona para todos os sistemas operacionais):
java -jar selenium-server-standalone-2.47.1.jar -role hub
Caso o comando não funcione, provavelmente é porque ainda não tem instalado o Java na máquina ou não configurou bem as varáveis de ambiente.
Se tudo ocorreu bem, a mensagem apresentada será semelhante à Figura 4.
Repare na linha em destaque que o Selenium Standalone Server nos forneceu o endereço, que servirá para registar os Nodes ao Hub central.
Se colocarmos no navegador o endereço http://192.168.0.6:4444/grid/console, podemos observar quais nodes estão sob controle do Hub central, além das suas configurações, como mostra a Figura 5.
Precisamos agora virtualizar duas máquinas utilizando o VirtualBox e depois fazer as configurações de Nodes nelas. Baixe ISO do VirtualBox na versão do sistema operacional da máquina local (vide seção Links), que no nosso caso é o Ubuntu em sua versão “14.10” 32 bits.
Com o programa aberto, clique em Novo e informe dentro do VirtualBox o valor “ubuntu 1” no campo nome e selecione a versão “Ubuntu (32 bits)”, como na Figura 6.
Após clicar em próximo, a tela seguinte será para informar o tamanho da memória. Como serão configuradas duas máquinas, selecione apenas ¼ da memória total e clique em “Próximo >”.
Na nova tela configuraremos o HD: certifique-se que as opções a seguir serão marcadas nas próximas telas:
- opção “Criar um disco rígido virtual agora” e clique em “Criar”;
- tipo de arquivo de disco rígido de ser o “VDI (VirtualBox Disk Image)”;
- o tipo “Armazenamento em disco rígido físico” deve ser selecionado;
- o tamanho deve ser “Tamanho Fixo”;
- para a tela de “Localização e tamanho do arquivo” deixe o mínimo recomendável, que no caso são 8 GB para o Ubuntu, em seguida clique em “Criar”.
Depois de termos criado a nossa máquina virtual, selecione-a na janela principal do VirtualBox e depois clique no menu “Configurações”. Na janela aberta selecione o item “Rede” no lado esquerdo e depois clique na aba “Adaptador 1” e, logo em seguida, na opção “Conectado a:” escolha o item “Placa em modo Bridge”, como mostra a Figura 7.
Ainda com a opção “ubuntu 1” selecionada, clique no menu de opções “Iniciar (T)” para iniciar a instalação do Ubuntu. Assim, uma janela como a Figura 8 é apresentada. Selecione o local onde está a ISO ou disco de instalação e depois clique em “Iniciar”.
Para criar a segunda máquina virtual basta repetir os mesmos passos, porém, use o nome “ubuntu 2”. Após a criação, instale o Java em ambas e os respectivos browsers, de acordo com as instruções passadas no início do artigo.
Para o Chrome, vamos baixar o driver direto do site do Selenium (vide seção Links). Vá até a seção “Third Party Drivers, Bindings, and Plugins → Browser” e clique no link chromedriver_linux32.zip. Este driver é necessário para facilitar a comunicação do navegador com o Selenium Standalone Server (Hub central). Após baixar realize a configuração com os seguintes comandos:
- No Ubuntu) e Mac OS X:
export PATH=$PATH:/caminho/para/chromedriver
- No Windows:
PATH=$PATH;\caminho\para\chromedriver
Para o Firefox não precismos baixar ou configurar nenhum driver.
Para configurar os nodes nas máquinas virtuais e ligá-las a Hub central precisamos executar um comanda Java em cada máquina virtual. Para o Node 1 execute o seguinte comando:
java -jar selenium-server-standalone-2.47.1.jar -role node -hub
http://192.168.0.6:4444/grid/register -browser browserName="firefox",
maxInstances=1,platform=LINUX
E para o Node 2 execute o comando:
java -jar selenium-server-standalone-2.47.1.jar -role node -hub
http://192.168.0.6:4444/grid/register -browser browserName="chrome",
maxInstances=1,platform=LINUX
Note que o valor “http://192.168.0.6:4444/grid/register” a frente do comando -hub se refere ao endereço do Hub central, assim fizemos o registro ao Hub central.
Repare também que no comando “-browser” definimos ao atributo -browserName o nome do navegador que estará apto para a executar os testes funcionais da aplicação web.
Ao final podemos visualizar no endereço http://192.168.0.6:4444/grid/console os Nodes que registramos, como mostra a Figura 9.
Criando o projeto
No Eclipse pressione CTRL+N e selecione o item Project Maven. Ao clicar em "Next >" uma nova janela se abrirá e nela marque o checkbox "Create a simple project" e clique em "Next"novamente. Uma nova tela aparecerá e deve ser preenchida conforme mostra a Figura 10.
Para adicionar as dependências no POM do Maven abra o pom.xml e acrescente o código da Listagem 1 entre as tags . Logo após execute o “Maven Update Project” utilizando o ALT+F5.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- Versão do plugin maven -->
<version>3.3</version>
<configuration>
<!-- Versão do java -->
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<!-- Versão do selenium -->
<selenium.version>2.47.1</selenium.version>
</properties>
<dependencies>
<!-- Selenium -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
<scope>test</scope>
</dependency>
<!--Driver do Selenium remoto -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-remote-driver</artifactId>
<version>${selenium.version}</version>
<scope>test</scope>
</dependency>
<!-- TestNG -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.6</version>
<scope>test</scope>
</dependency>
</dependencies>
Criando as classes principais
Precisamos agora criar a estrutura de pacotes da Figura 11 em nosso projeto no diretório /projeto-maven/src/main/java.
Na Interface EstabelecerDriver.java precisamos adicionar o código da Listagem 2 para definir as propriedades que o WebDriver usará para acessar o browser. Assim, ao solicitar uma nova sessão, o cliente pode especificar o browser e a plataforma a serem usadas.
public interface EstabelecerDriver {
//Declarações de métodos
WebDriver obterObjetoWebDriver(DesiredCapabilities desiredCapabilities);
WebDriver obterObjetoWebDriverRemoto(DesiredCapabilities desiredCapabilities,
Platform plataforma, String enderecoRemoto);
DesiredCapabilities obterCapacidadesDesejadas();
}
Para o Enum TipoDriver adicionaremos o código da Listagem 3. Este servirá para definir tipos de drivers, que contém métodos úteis dos quais iremos utilizar nas classes de testes para a chamada de instâncias de WebDriver's (Firefox e Chrome).
public enum TipoDriver implements EstabelecerDriver {
FIREFOX {
public DesiredCapabilities obterCapacidadesDesejadas() {
DesiredCapabilities capabilities = DesiredCapabilities.firefox();
return capabilities;
}
public WebDriver obterObjetoWebDriver(DesiredCapabilities capabilities) {
return new FirefoxDriver(capabilities);
}
public WebDriver obterObjetoWebDriverRemoto(
DesiredCapabilities capabilities, Platform plataforma,
String enderecoRemoto) {
capabilities.setPlatform(plataforma);
WebDriver driver = null;
try {
driver = new RemoteWebDriver(new URL(enderecoRemoto),
capabilities);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return driver;
}
},
CHROME {
public DesiredCapabilities obterCapacidadesDesejadas() {
DesiredCapabilities capabilities = DesiredCapabilities.chrome();
capabilities.setCapability("chrome.switches",
Arrays.asList("--no-default-browser-check"));
HashMap<String, String> chromePreferences = new HashMap<String, String>();
chromePreferences.put("profile.password_manager_enabled", "false");
capabilities.setCapability("chrome.prefs", chromePreferences);
// Fim
return capabilities;
}
public WebDriver obterObjetoWebDriver(DesiredCapabilities capabilities) {
return new ChromeDriver(capabilities);
}
public WebDriver obterObjetoWebDriverRemoto(
DesiredCapabilities capabilities, Platform plataforma,
String enderecoRemoto) {
capabilities.setPlatform(plataforma);
WebDriver driver = null;
try {
driver = new RemoteWebDriver(new URL(enderecoRemoto),
capabilities);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return driver;
}
}
A seguir temos alguns detalhes importantes sobre esse código:
- Linha 5: temos o método que retorna as capacidades para usar o Firefox;
- Linha 10: temos o método que retorna uma instância do Driver do Firefox para uso;
- Linha 15: temos o método que retorna um objeto remoto;
- Linha 19: Define o sistema operacional;
- Linha 23: Atribuição da instância do objeto remoto WebDriver, com o retorno na linha 31;
- Linha 37: temos o método que retorna as capacidades para usar o Chrome;
- Linhas 40 a 47: temos neste bloco a definição de alguns comandos para o Google Chrome, pois não queremos aquela pergunta de definição do navegador padrão e nem que o gerenciador de senhas pergunte se gostaria de salvar os dados de login cada vez que um teste executar uma ação de login;
- Linha 52: método que retorna uma instância do Driver do Chrome para uso;
- Linha 56: método que retorna um objeto WebDriver remoto.
Note que ao lado do nome do Enum TipoDriver existe a definição implements EstabelecerDriver: isso quer dizer que o Enum TipoDriver está assinando um contrato com a interface EstabelecerDriver e, como consequência, irá definir todos os métodos declarados na interface. Contudo, conseguimos definir os Enums FIREFOX e CHROME, que serão úteis na criação das classes testes.
Partiremos para a criação de outro pacote com a estrutura semelhante à Figura 12 no diretório /projeto-maven/src/main/java. Este servirá para colocarmos a classe de apoio ConversorTemperatura, que conterá métodos de conversão de temperatura, úteis para as classes de testes.
Na Listagem 4 temos o código da classe ConversorTemperatura.java, que fornecerá os resultados de cálculos de conversão de temperatura.
public class ConversorTemperatura {
private final static Integer SCALE = 6;
private static Double valor = null;
public static Double aplicarScala(Double valor) {
// Atribui um BigDecimal que recebendo o valor de um Double e que ao
// final é lhe aplicado um escala
BigDecimal bd = new BigDecimal(valor).setScale(SCALE,
RoundingMode.HALF_EVEN);
// retorna o valor em Double
return bd.doubleValue();
}
// Conversão do valor de Celsius para Fahrenheit
public static String celsiusParaFahrenheit(String celsius) {
// Atribui o valor em Double convertida de uma String
valor = Double.parseDouble(celsius);
// Retorna uma String convertida de um valor Double onde lhe foi
// aplicado uma escala
return String.valueOf(aplicarScala(1.8 * valor + 32.0));
}
// Conversão do valor de Fahrenheit para Celsius
public static String fahrenheitParaCelsius(String fahrenheit) {
// Atribui o valor em Double convertida de uma String
valor = Double.parseDouble(fahrenheit);
// Retorna uma String convertida de um valor Double onde lhe foi
// aplicado uma escala
return String.valueOf(aplicarScala((5.0 * (valor - 32.0) / 9.0)));
}
}
O Método aplicarScala aplica a escala no valor Double, ou seja, o resultado do valor 51.12313121323123 ficará 51.123131, com no máximo seis dígitos após a vírgula.
Na Figura 13 vemos o novo pacote e as classes que precisamos criar no diretório /projeto-maven/src/main/java. Nessas classes incluiremos o mapeamento das páginas da aplicação web utilizando o Selenium WebDriver, bem como métodos úteis, isso porque criaremos os testes funcionais com base nelas.
A Listagem 5deve ser incluída na classe PaginaInicio e tem como objetivo fazer referência a página Início da aplicação (http://artigo.pe.hu).
public class PaginaInicio {
@FindBy(how = How.ID, using = "conversor")
private WebElement menuOpcaoConversor;
@FindBy(how = How.ID, using = "temperatura")
private WebElement menuOpcaoConversorTemperatura;
private WebDriver driver;
public PaginaInicio(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
this.driver.get("http://artigo.pe.hu");
}
public PaginaConversorTemperatura irParaPaginaConversorTemperatura() {
Actions acoesAvancadasDeUsuario = new Actions(driver);
WebDriverWait wait = new WebDriverWait(driver, 10);
acoesAvancadasDeUsuario.moveToElement(menuOpcaoConversor).perform();
wait.until(ExpectedConditions
.visibilityOf(menuOpcaoConversorTemperatura));
acoesAvancadasDeUsuario.moveToElement(menuOpcaoConversorTemperatura)
.click().perform();
return new PaginaConversorTemperatura(driver);
}
}
Na linha 2 começa o mapeamento entre o objeto WebElement com o elemento HTML que tem o id="conversor"na página web. Na linha 4 temos o mesmo tipo de mapeamento, mas com o id="temperatura".
Na linha 7 temos a implementação do construtor com a atribuição do parâmetro que tem a instância para o objeto do WebDriver corrente
O comando da linha 9 permite que os atributos mapeados nesta classe com @FindBy sejam carregados com os elementos HTML correspondentes para iniciar o navegador com o endereço web.
Na linha 14 inicializa-se o objeto Actions para uso com o WebDriver corrente, assim como a linha 15, que inicializa o objeto WebDriverWait para uso com o Webdriver corrente. No construtor da classe, além de ser definido o Webdriver, foi também definido o tempo de espera de 10 segundos. Se passar disso é lançada uma exception até que os itens do menu Conversor apareçam. Quando isso acontecer, clique no item Conversor de Temperatura.
As ações ocorrem em tempo real na aplicação web e para satisfazer o retorno do método, o objeto da classe PaginaConversorTemperatura deve ser retornado com o driver corrente.
Na classe PaginaConversorTemperatura.java precisamos incluir o código da Listagem 6, pois esta fará referência à Página Conversor de Temperatura (http://artigo.pe.hu/?pg=conv_temperatura.php).
public class PaginaConversorTemperatura {
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="valuefromtemperature1" na página web
@FindBy(how = How.ID, using = "valuefromtemperature1")
private WebElement valorEntrada;
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="selectfromtemperature1" na página web
@FindBy(how = How.ID, using = "selectfromtemperature1")
private WebElement webSelectDe;
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="selecttotemperature1" na página web
@FindBy(how = How.ID, using = "selecttotemperature1")
private WebElement webSelectPara;
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="valuetotemperature1" na página web
@FindBy(how = How.ID, using = "valuetotemperature1")
private WebElement resultado;
// WebDriver
private WebDriver driver;
// Implementação do construtor
public PaginaConversorTemperatura(WebDriver driver) {
// Atribuição do parametro que tem instância do WebDriver, para o objeto
// WebDriver que tem o escopo desta classe
this.driver = driver;
// Permite que os atributos mapeados nesta classe com @FindBy sejam
// carregados com os elementos html correspondente
PageFactory.initElements(this.driver, this);
// Carrega e inicia o navegador com o endereço web
this.driver.get("http://artigo.pe.hu/?pg=conv_temperatura.php");
}
public void preencherValorDeEntrada(String i) {
// Comando que envia valores para o elemento html
valorEntrada.sendKeys(i);
}
public WebElement obterValorDeEntrada() {
// retorna objeto WebElement
return valorEntrada;
}
public Select obterSelectDeTemperatura() {
// Retorna um objeto Select que faz referência ao elemento html Select
// na página web
return new Select(webSelectDe);
}
public Select obterSelectParaTemperatura() {
// Retorna um objeto Select que faz referência ao elemento html Select
// na página web
return new Select(webSelectPara);
}
public WebElement obterResultadoTemperatura() {
// retorna objeto WebElement
return resultado;
}
}
A classe PaginaTrabalheConosco está presente no código da Listagem 7 e tem como objetivo fazer referência a Página Trabalhe Conosco (http://artigo.pe.hu/?pg=trabalhe_conosco.php).
public class PaginaTrabalheConosco {
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="nome" na página web
@FindBy(how = How.ID, using = "nome")
private WebElement nome;
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="email" na página web
@FindBy(how = How.ID, using = "email")
private WebElement email;
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="opcaoMasculino" na página web
@FindBy(how = How.ID, using = "opcaoMasculino")
private WebElement opcaoSexoMasculino;
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="checkIngles" na página web
@FindBy(how = How.ID, using = "checkIngles")
private WebElement checkIdiomaIngles;
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="selectOpcaoVaga" na página web
@FindBy(how = How.ID, using = "selectOpcaoVaga")
private WebElement selectOpcaoVaga;
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="arquivoCurriculo" na página web
@FindBy(how = How.ID, using = "arquivoCurriculo")
private WebElement arquivoCurriculo;
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="botaoEnviar" na página web
@FindBy(how = How.ID, using = "botaoEnviar")
private WebElement botaoEnviar;
// Mapeamento entre o objeto WebElement com o elemento html que tem o
// id="msgAposEnvio" na página web
@FindBy(how = How.ID, using = "msgAposEnvio")
private WebElement msgAposEnvio;
// WebDriver
private WebDriver driver;
// Implementação do construtor
public PaginaTrabalheConosco(WebDriver driver) {
// Atribuição do parametro que tem instância do WebDriver, para o objeto
// WebDriver que tem o escopo desta classe
this.driver = driver;
// Permite que os atributos mapeados nesta classe com @FindBy sejão
// carregados com os elementos html correspondente
PageFactory.initElements(this.driver, this);
// Carrega e inicia o navegador com o endereço web
this.driver.get("http://artigo.pe.hu/?pg=trabalhe_conosco.php");
}
public void preencherNome(String nomeValor) {
// Comando que envia valores para o elemento html
nome.sendKeys(nomeValor);
}
public void preencherEmail(String emailValor) {
// Comando que envia valores para o elemento html
email.sendKeys(emailValor);
}
public void marcarRadioButtonSexoMasculino() {
// Comando que clica no elemento html
opcaoSexoMasculino.click();
}
public void marcarCkeckBoxIdiomaIngles() {
// Comando que clica no elemento html
checkIdiomaIngles.click();
}
public void selecionarVaga(String vaga) {
// Atribuição de objeto Select que faz referência ao elemento html
// Select
Select selOpcaoVaga = new Select(selectOpcaoVaga);
// Comando que marca a opção do select que tem o texto x visível na
// página web
selOpcaoVaga.selectByVisibleText(vaga);
}
public void selecionarArquivoCurriculo(String urlAbsolutaDoArquivoPdf) {
// Comando que envia valores para o elemento html
arquivoCurriculo.sendKeys(urlAbsolutaDoArquivoPdf);
}
public void enviarMensagemDeTrabalheConosco() {
// Comando que clica no elemento html
botaoEnviar.click();
}
public String obterMensagemAposEnvio() {
// Comando retorna o texto visível do elemento html
return msgAposEnvio.getText();
}
}
Criação dos testes
Para os nossos testes criaremos duas classes no diretório /projeto-maven/src/test/java, conforme a estrutura vista na Figura 14.
A classe TestePaginaTrabalheConosco.java, presente na Listagem 8, irá executar os testes funcionais da página Trabalhe conosco no navegador Firefox do Node 1, então, certifique-se que o endereço da primeira máquina virtual está igual ao valor do parâmetro do método obterObjetoWebDriverRemoto(), que está dentro do método inicializarDriver() da classe TestePaginaTrabalheConosco. Lembre-se que os endereços dos Nodes podem ser visualizados em http://192.168.0.6:4444/grid/console (Selenium Standalone Server).
public class TestePaginaTrabalheConosco {
// Declaração de variável
WebDriver driver;
@BeforeClass
public void inicializarDriver() throws Exception {
// Atribuição da instância do Enum do Tipo Firefox
TipoDriver selecionadoTipoDriver = TipoDriver.FIREFOX;
// Atribuição das capacidades para usar o tipo driver Firefox
DesiredCapabilities capacidadesDesejadas = selecionadoTipoDriver
.obterCapacidadesDesejadas();
driver = selecionadoTipoDriver.obterObjetoWebDriverRemoto(
capacidadesDesejadas, Platform.LINUX,
"http://192.168.0.9:5555/wd/hub");
/**
* driver =
* selecionadoTipoDriver.obterObjetoWebDriver(capacidadesDesejadas);
*/
}
@AfterClass
public void fecharDriver() {
if (null != driver) {
driver.quit();
}
}
@Parameters({ "nomeParametro" })
// Executa o método como teste
@Test
public void testeEnviarMensagemDeTrabalheConosco(String nomeParametro) {
PaginaTrabalheConosco paginaTrabalheConosco = new PaginaTrabalheConosco(
driver);
// Preenche o campo nome
paginaTrabalheConosco.preencherNome(nomeParametro);
// Preenche o campo email
paginaTrabalheConosco.preencherEmail("brendo10x@gmail.com");
// Marca a opção do radio button
paginaTrabalheConosco.marcarRadioButtonSexoMasculino();
// Marca a opção do checkbox
paginaTrabalheConosco.marcarCkeckBoxIdiomaIngles();
// Seleciona a opção do select
paginaTrabalheConosco.selecionarVaga("Suporte de TI");
// Escolhe o arquivo pdf
paginaTrabalheConosco
.selecionarArquivoCurriculo("/home/brendo/curriculo.pdf");
// Clica no botão para enviar o formulário com as informações acima
paginaTrabalheConosco.enviarMensagemDeTrabalheConosco();
// Retorna a mensagem informada na página conversor temperatura
String msg = paginaTrabalheConosco.obterMensagemAposEnvio();
// Verifica se são iguais, o resultado com o esperado
Assert.assertEquals(msg, "Sucesso!");
}
}
No primeiro método a ser chamado na classe é anotado com @BeforeClass do TestNG. Em seguida, é atribuída a instância do Enum do Tipo Firefox e as capacidades para usar o tipo driver(Firefox).
Há a atribuição do WebDriver remoto, com as definições de que os testes funcionais desta classe serão executados no navegador Google Chrome do Node http://192.168.0.9:5555/wd/hub (1ª máquina virtual usando Linux.
Descomente o seguinte trecho de código e comente o anterior caso deseje testar esta classe no seu computador.
/**
* driver =
* selectedDriverType.obterObjetoWebDriver(desiredCapabilities);
*/
O último método fecharDriver() é executado, pois está anotado com @AfterClass do TestNG. Ele verifica se o driver é diferente null e se for, fecha o driver, ou seja o navegador que está em execução.
Na linha @Parameters({ "nomeParametro"}) temos a definição de parâmetro para que o método testeEnviarMensagemDeTrabalheConosco receba a partir do arquivo do testng.xml (do TestNG) declarado neste projeto.
Na Listagem 9 temos o código da classe TestePaginaConversorTemperatura, que irá executar os testes funcionais no navegador Google Chrome do Node 2.
public class TestePaginaConversorTemperatura {
private Select selectDe;
private Select selectPara;
private WebElement resultado;
private WebElement entrada;
private WebDriver driver;
private String resultadoValor;
private String resultadoCalculado;
@BeforeClass
public void inicializarDriver() throws Exception {
TipoDriver selecionadoTipoDriver = TipoDriver.CHROME;
DesiredCapabilities capacidadesDesejadas = selecionadoTipoDriver
.obterCapacidadesDesejadas();
driver = selecionadoTipoDriver.obterObjetoWebDriverRemoto(
capacidadesDesejadas, Platform.LINUX,
"http://192.168.0.2:5555/wd/hub");
/**
* driver =
* selecionadoTipoDriver.obterObjetoWebDriver(capacidadesDesejadas);
*/
}
@AfterClass
public void fecharDriver() {
if (null != driver) {
driver.quit();
}
}
@Parameters({ "entradaParametro" })
// Executa o método como teste
@Test
public void testeCalcularConversorTemperatura(String entradaParametro)
throws Exception {
// Este teste executa como se fosse passos de usuário
// Inicia a página inicial
PaginaInicio paginaInicio = new PaginaInicio(driver);
// Depois vai, da página inicial até a página Converso de Temperatura
PaginaConversorTemperatura paginaConversorTemperatura = paginaInicio
.irParaPaginaConversorTemperatura();
// Estando na página Conversor de temperatura
// Preencha o campo com o valor de entrada
paginaConversorTemperatura.preencherValorDeEntrada(entradaParametro);
// Atribui o valor de entrada a partir da referência do elemento html
entrada = paginaConversorTemperatura.obterValorDeEntrada();
// Atribui a referência do elemento html Select
selectDe = paginaConversorTemperatura.obterSelectDeTemperatura();
// Atribui a referência de outro elemento html Select
selectPara = paginaConversorTemperatura.obterSelectParaTemperatura();
// Por fim, atribui do valor do resultado a partir da referência do
// elemento html
resultado = paginaConversorTemperatura.obterResultadoTemperatura();
}
// Este teste só executa depois que o método
// testeCalcularConversorTemperatura executar, pois este teste depende da
// execução dele.
@Test(dependsOnMethods = { "testeCalcularConversorTemperatura" })
public void testeCelsiusParaCelsius() {
// Esses dois primeiros métodos, selecionam a opção do elemento
// html Select que tiver com x texto vísivel na aplicação web.
selectDe.selectByVisibleText("Celsius [°C]");
selectPara.selectByVisibleText("Celsius [°C]");
// Verifica se são iguais, o resultado com o esperado (valor de entrada)
Assert.assertEquals(resultado.getAttribute("value"),
entrada.getAttribute("value"));
}
// Este teste só executa depois que o método
// testeCalcularConversorTemperatura executar, pois este teste depende da
// execução dele.
@Test(dependsOnMethods = { "testeCalcularConversorTemperatura" })
public void testeCelsiusParaFahrenheit() {
// Esses dois primeiros métodos, selecionam a opção do elemento
// html Select que tiver com x texto visível na aplicação web.
selectDe.selectByVisibleText("Celsius [°C]");
selectPara.selectByVisibleText("Fahrenheit [°F]");
// Atribui o valor do atributo value do elemento html
resultadoValor = resultado.getAttribute("value");
// Atribui o resultado da conversão
resultadoCalculado = ConversorTemperatura.celsiusParaFahrenheit(entrada
.getAttribute("value"));
// Verifica se são iguais, o resultado com o esperado
Assert.assertEquals(resultadoValor, resultadoCalculado);
}
// Este teste só executa depois que o método
// testeCalcularConversorTemperatura executar, pois este teste depende da
// execução dele.
@Test(dependsOnMethods = "testeCalcularConversorTemperatura")
public void testeFahrenheitParaCelsius() {
// Esses dois primeiros métodos, selecionam a opção do elemento
// html Select que tiver com x texto vísivel na aplicação web.
selectDe.selectByVisibleText("Fahrenheit [°F]");
selectPara.selectByVisibleText("Celsius [°C]");
// Atribui o valor do atributo value do elemento html
resultadoValor = resultado.getAttribute("value");
// Atribui o resultado da conversão
resultadoCalculado = ConversorTemperatura.fahrenheitParaCelsius(entrada
.getAttribute("value"));
// Verifica se são iguais, o resultado com o esperado
Assert.assertEquals(resultadoValor, resultadoCalculado);
}
// Este teste só executa depois que o método
// testeCalcularConversorTemperatura executar, pois este teste depende da
// execução dele.
@Test(dependsOnMethods = { "testeCalcularConversorTemperatura" })
public void testeFahrenheitParafahrenheit() {
// Esses dois primeiros métodos, selecionam a opção do elemento
// html Select que tiver com x texto visível na aplicação web.
selectDe.selectByVisibleText("Fahrenheit [°F]");
selectPara.selectByVisibleText("Fahrenheit [°F]");
// Verifica se são iguais, o resultado com o esperado (valor de entrada)
Assert.assertEquals(resultado.getAttribute("value"),
entrada.getAttribute("value"));
}
Execução dos testes
Antes de executarmos os testes, certifique-se que os Nodes e o Hub central estão funcionando corretamente. Lembre-se que o TestNG deve estar instalado no seu Eclipse (vide seção Links).
Agora, termos que criar um arquivo de configuração do TestNG para dizermos a ele quais classes de testes serão executadas. Sendo assim, crie um arquivo chamado testng.xml no diretório /projeto-maven/src/test/resources e, em seguida cole o código da Listagem 10 no arquivo testng.xml.
<suite name="Suite de teste" parallel="tests" thread-count="2">
<test name="Teste na primeira máquina">
<parameter name="entradaParametro" value="2" />
<classes>
<class
name="br.com.aprendendo.selenium.testepaginas.TestePaginaConversorTemperatura" />
</classes>
</test>
<test name="Teste na segunda máquina">
<parameter name="nomeParametro" value="Brendo Felipe" />
<classes>
<class
name="br.com.aprendendo.selenium.testepaginas.TestePaginaTrabalheConosco" />
</classes>
</test>
</suite>
Observe que no arquivo criado declaramos na tag dois atributos importantes: o parallel="tests" e thread-cont="2". Isso significa que o TestNG fará o lançamento ou execução dos testes de forma paralela. Com isso, fizemos um “Aperfeiçoamento” e os testes serão iniciados e executados ao mesmo tempo, no respectivo navegador.
Neste momento, o nosso projeto já está pronto e agora vamos executar os nossos testes funcionais distribuídos. Para isso, primeiro selecione o arquivo testng.xml e em seguida clique com o botão direto e escolha as opções Run As → TestNG Suite.
Como mostra a Figura 15 todos os testes passaram. Assim, vimos na prática como agilizar os nossos testes e otimizar o desenvolvimento das nossas aplicações.