Trabalhando com testes funcionais distribuídos em Java

Neste artigo desenvolveremos testes funcionais distribuídos de uma aplicação web, ou seja, executando suíte de testes em diferentes máquinas (virtuais) em paralelo. Para isso usaremos Selenium Grid e WebDriver, bem como o TestNG e o VirtualBox.

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.

Figura 1. Arquitetura do Selenium WebDriver

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:

Vejamos na Figura 2 a arquitetura do Selenium Grid.

Figura 2. 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 :

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:

  1. 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;
  2. Criação de um novo projeto no Eclipse com Maven utilizando o Java 8;
  3. Criação das classes utilizando o Selenium WebDriver;
  4. 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.

Figura 3. Fluxo de execução da visão geral

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.

Figura 4. Mensagem de sucesso

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.

Figura 5. Página web que exibe o(s) Node(s) ligado(s) ao Hub central

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.

Figura 6. VirtualBox e o “Nome e Sistema Operacional” da máquina virtual

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:

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.

Figura 7. Configurações de rede

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”.

Figura 8. Seleção do disco rígido de boot

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:

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.

Figura 9. Selenium Standalone Server (Hub central) exibindo os Nodes registrados

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.

Figura 10. Configurações do projeto Maven

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>
Listagem 1. Dependências do projeto

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.

Figura 11. Estrutura de pacote

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(); }
Listagem 2. Código da Interface EstabelecerDriver.java

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; } }
Listagem 3. Código do Enum TipoDriver

A seguir temos alguns detalhes importantes sobre esse código:

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.

Figura 12. Pacote .apiconversor

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))); } }
Listagem 4. Código da classe ConversorTemperatura.java

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).

Figura 13. Estrutura do pacote .fabricaobjetivopagina
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); } }
Listagem 5. Código da classe PaginaInicio.java

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; } }
Listagem 6. Código da PaginaConversorTemperatura.java

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(); } }
Listagem 7. Código da classe PáginaTrabalheConosco

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.

Figura 14. Estrutura do pacote .testepaginas

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!"); } }
Listagem 8. Código da TestePaginaTrabalheConosco.java

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")); }
Listagem 9. Código da classe de TestePaginaConversorTemperatura.java

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>
Listagem 10. Código do arquivo testng.xml

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 AsTestNG Suite.

Figura 15. Mostra o resultado dos testes

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.

Artigos relacionados