Por que eu devo ler este artigo:

A automação de testes soma praticamente 20% do tempo de trabalho de um testador (ou desenvolvedor testador) e economiza várias horas de manutenção e de testes de regressão para verificar se tudo está funcionando há cada nova release de software lançada. O Selenium se popularizou como um dos principais frameworks de automação de testes do mercado, principalmente pelo seu suporte a linguagens como Python, Ruby, Java, C# e Node.js.

Neste artigo aprenderemos a configurar o Selenium de duas formas: via IDE Eclipse e via Selenium IDE. Você verá como gravar testes nos browsers, salvar scripts, re-executá-los, além de comunicar seus testes com JavaScript, jQuery e HTML5. Ao final deste, o leitor estará apto a executar testes síncrona e assincronamente via API, linha de comando ou interface gráfica, além de entender que tipo de teste se encaixa melhor em cada realidade de software.

A automação de testes existe para, através de ferramentas e estratégias, reduzir ao máximo o envolvimento humano em atividades manuais repetitivas, como o cadastro de um cliente ou o login/logout em uma aplicação.


Guia do artigo:

O principal objetivo de um teste automatizado é ser usado futuramente em testes de regressão. Esse termo, por sua vez, é usado para quando precisamos efetuar ciclos de re-teste de uma ou várias funcionalidades, com a intenção de identificar problemas ou defeitos introduzidos pela adição de novas funcionalidades ou pela correção de alguma já existente.

Levando em consideração um exemplo real, quando um projeto de software não utiliza testes automatizados em sua concepção, sempre que uma alteração acontece em determinada tela ou módulo, um novo ciclo de testes manuais precisa ser refeito e, assim, sucessivamente até que o projeto esteja terminado. O problema aumenta mais ainda quando o projeto não tem fim e exige manutenção constante, implicando consequentemente em mais custos com uma equipe de teste e possivelmente em entregas sem qualidade, já que não houve tempo o suficiente para testar e re-testar tudo.

Em contrapartida, a utilização de testes automatizados acelera os ciclos do software, uma vez que o teste passa a ser executado por outro software inteligente, que acessa as telas e reexecuta os mesmos testes nos dando relatórios rápidos do que deixou de funcionar. Além disso, estamos menos suscetíveis a erros, já que a máquina nunca erra, ao contrário de termos humanos testando.

Existem várias abordagens diferentes para a automação de testes. Os tipos são normalmente agrupados de acordo com a maneira com a qual os testes se integram e interagem com o software. Um testador pode construir seu teste baseando-se em dois conceitos:

  1. Interface gráfica
    1. Gravação/Execução (Capture/Playback): os testes são feitos diretamente na interface gráfica da aplicação: HTML, XML, Swing, etc. As ferramentas geralmente disponibilizam recursos para efetuar a gravação (capture) das ações feitas nas telas que serão convertidas para uma linguagem de script inteligível pela mesma, a qual poderá futuramente ser reexecutada (playback).
    2. Dirigido a dados (Data-Drive): representa uma abordagem mais dirigida aos dados no sentido de gravar as ações do usuário, porém sempre fornecendo dados distintos para deixar o teste mais próximo da realidade.
    3. Dirigido a palavras-chave (Keyword-Driven): são testes com alto nível de abstração, onde até mesmo usuários comuns podem criar instruções para iniciar um teste, uma vez que o mesmo será baseado em palavras-chave. Cada palavra-chave representa um comando da ferramenta.
  2. Lógica de negócio
    1. Linha de comando (Command Line Interface): fornece uma interface com um mecanismo de interação com a aplicação por meio de um prompt cmd do SO e os comandos podem ser enviados de lá.
    2. API (Application Programming Interface): fornece bibliotecas ou um conjunto de classes para permitir que outras aplicações acessem a interface do teste sem necessariamente ter de conhecer como eles foram feitos.
    3. Test Harness (Equipamentos de teste): é um teste específico que visa o teste único e exclusivo da lógica de negócio. Não é permitida interação alguma com as interfaces gráficas.

O sucesso desse tipo de teste depende de identificar e alocar elementos da GUI (Graphical User Interface) na aplicação a ser testada e então executar operações e verificações nestes mesmos elementos para que o fluxo do teste seja completado com sucesso.

O Selenium é um framework de testes automatizados portável para aplicações web desenvolvido em 2004 por Jason Huggins como um projeto interno da empresa ThougthWorks. Ele fornece todo o aparato para capturar e reproduzir os testes via scripts sem a necessidade de aprender nenhuma linguagem de scripting. Também disponibiliza uma linguagem de teste específica para linguagens populares como Java, C#, Groovy, Perl, PHP, Python e Ruby. Os testes podem ser executados em browsers web modernos e os deploy de aplicação rodam tanto em Windows, quanto em Linux e Macintosh.

Dentre a lista de funcionalidades fornecida pelo framework, temos:

  • Preenchimento de caixas de texto;
  • Checagem de checkboxes e botões de rádio;
  • Click em botões e links;
  • Navegação de e para <iframe>’s;
  • Navegação de e para novas janelas/tabs criadas por links;
  • Interação com a maioria dos elementos como um humano faz.

Na lista de funcionalidades que ele não suporta, temos:

  • Interação com Flash, PDF ou Applets;
  • Interação com quaisquer objetos colocados dentro das tags HTML <object> e <embed>.

Neste artigo exploraremos os principais recursos desse framework, através da construção de exemplos reais usando as linguagens JavaScript, jQuery e Java em conjunto com HTML5 e testes efetuados no Google Chrome e Firefox. Veremos desde a configuração e instalação da ferramenta, bem como as principais diferenças entre usar o Selenium embarcado (com uma linguagem de programação) e o Selenium IDE (diretamente no browser Firefox como Add-On).

Configuração do ambiente

O primeiro requisito obrigatório para executar o Selenium no seu Sistema Operacional é ter uma versão recente do JDK (Java Development Kit) instalada. Para verificar se você já tem alguma, basta acessar o terminal de comandos e digitar o seguinte comando:


        java -version
        

Se você vir um número com a versão do Java sendo impresso, então você já o tem instalado. Caso contrário, acesse a página de downloads do mesmo (seção Links) e efetue os passos para instalação (você encontrará tutoriais de como instalar no próprio site da Oracle caso tenha alguma dúvida).

Em seguida, precisamos efetuar o download do Eclipse (seção Links), que é a IDE mais utilizada para desenvolver com o Selenium. Selecione sempre a opção “Eclipse IDE for Java EE Developers”, dessa forma teremos uma versão da IDE que também desenvolve para a web. Certifique-se também de baixar a versão correspondente com o seu Sistema Operacional (32/64 bits). Quando finalizar o download, mova o arquivo zip baixado e o descompacte em um local de sua preferência. Como não é preciso instalá-lo, basta dar clique duplo no arquivo eclipse.exe e a ferramenta irá iniciar.

Por fim, precisamos selecionar também os jars do Selenium para termos pleno suporte ao mesmo dentro dos projetos. Optaremos por usar o Java como linguagem server side, em vista de a imensa maioria dos usuários do Selenium usarem essa linguagem no mercado por padrão. Portanto, acesse a página de download do Selenium (seção Links) e na seção “Selenium Client & WebDriver Language Bindings” clique no link correspondente à linguagem Java (Figura 1).

Página de download do WebDriver do Selenium
Figura 1. Página de download do WebDriver do Selenium.

O arquivo baixado estará também no formato zip, logo extraia-o novamente no diretório do projeto. A Figura 2 mostra a representação dos arquivos internos, dos quais faremos uso essencialmente dos jars.

Estrutura de pastas e arquivos do Selenium
Figura 2. Estrutura de pastas e arquivos do Selenium.

Execute agora o Eclipse e selecione um workspace para salvar o projeto. Após isso, vamos criar um primeiro exemplo de AloMundo com o browser Firefox. Seleciona a opção “File > New > Project > Java Project” e, na janela que aparecer, dê o nome “AloMundoSelenium” ao projeto e certifique-se de selecionar a opção JavaSE-7 no botão “Use na execution environment JRE”, conforme mostra a Figura 3.

Wizard de criação de novo projeto Selenium no
Eclipse
Figura 3. Wizard de criação de novo projeto Selenium no Eclipse.

Clique em “Finish”. Para que as nossas classes reconheçam o Selenium WebDriver, precisamos adicionar os jars ao classpath. Para isso, clique com o botão direito no projeto gerado e selecione “Properties > Java Build Path” e acesse a tab “Libraries”. Clique no botão “Add External JARS...” e navegue até as pastas onde você descompactou o Selenium. Selecione todos os jars da raiz do diretório e da pasta “libs” e clique em “Abrir” (Figura 4).

Libs do Selenium adicionadas ao projeto
Figura 4. Libs do Selenium adicionadas ao projeto.

Para fazer um teste rápido, vá até o diretório src do projeto, clique com o botão direito e selecione a opção “New > Class” e dê um nome de pacote (br.edu.devmedia.selenium) e um nome de classe “AloMundoSelenium” e clique em “Finish”. Na classe que for aberta, adicione o conteúdo da Listagem 1 à mesma.

Listagem 1. Classe de teste com o browser Firefox.

        package br.edu.devmedia.selenium;

        import java.io.File;

        import org.openqa.selenium.WebDriver;
        import org.openqa.selenium.chrome.ChromeDriver;
        import org.openqa.selenium.firefox.FirefoxDriver;
        import org.openqa.selenium.ie.InternetExplorerDriver;

        public class AloMundoSelenium {
        public static void main(String[] args) {
        abrirFirefox();
        }

        private static void abrirFirefox() {
        WebDriver driver = new FirefoxDriver();
        driver.get("http://devmedia.com.br");
        String i = driver.getCurrentUrl();
        System.out.println(i);
        driver.close();
        }

        }
        

O código traz uma representação simples de teste no Selenium que irá somente abrir uma instância do browser Firefox (linha 16), acessar o site da DevMedia (linha 17) e retornar a URL para o qual o mesmo foi redirecionado (linha 18). No final, ele fecha a conexão com o driver (linha 20). Para executar vá até o menu “Run” no topo da página ou clique com o botão direito na classe e selecione “Run As > Java Application”.

O resultado será a abertura de uma instância do browser citado com o respectivo site e a mensagem final impressa no console (Figura 5).

Resultado de execução do teste no Firefox
Figura 5. Resultado de execução do teste no Firefox.

O Selenium trabalha com o conceito de drivers para o browser a ser trabalhado. Nos projetos reais, geralmente temos código para lidar com ao menos três browsers: Firefox, Chrome e IE, que são os mais usados. Caso você queria adicionar uma nova instância, precisará também efetuar o download do driver dele, uma vez que o Selenium reconhece apenas o Firefox em vista da sua IDE ser desenvolvida nele. Para isso, efetue o download do arquivo chromedriver.exe na sua versão mais recente no endereço disponível na seção Links e posicione-o no endereço do workspace do projeto.

O código para acessar agora passa a ser igual ao da Listagem 2.

Listagem 2. Código para acessar a instância do Chrome.

        package br.edu.devmedia.selenium;
        import java.io.File;
        import org.openqa.selenium.WebDriver;
        import org.openqa.selenium.chrome.ChromeDriver;
        import org.openqa.selenium.firefox.FirefoxDriver;
        import org.openqa.selenium.ie.InternetExplorerDriver;
        public class AloMundoSelenium {
        public static void main(String[] args) {
        abrirChrome();
        }
        private static void abrirChrome() {
        File file = new File("D:/Downloads/chromedriver.exe");
        System.setProperty("webdriver.chrome.driver", file.getAbsolutePath());
        WebDriver driver = new ChromeDriver();
        driver.get("http://devmedia.com.br");
        String i = driver.getCurrentUrl();
        System.out.println(i);
        driver.close();
        }
        private static void abrirIE() {
        WebDriver driver = new InternetExplorerDriver();
        driver.get("http://devmedia.com.br");
        String i = driver.getCurrentUrl();
        System.out.println(i);
        driver.close();
        }
        }
        

Veja que na linha 6 temos a importação do arquivo do driver diretamente da pasta onde ele foi alocado e, em seguida, setamos a propriedade “webdriver.chrome.driver” nas propriedades do sistema com o valor do caminho do driver, para que o Selenium possa encontrar uma instância correta da classe ChromeDriver. O restante do procedimento é o mesmo. Na linha 25 vemos o equivalente para o browser do Internet Explorer, mas também será necessário baixar o driver do mesmo.

Um outro bom exemplo é quando queremos não só acessar uma página, como também enviar informações para ela, gerar submits e recuperar dados dos responses. Esse tipo de funcionalidade é possível através da classe HTMLUnitDriver, que funciona como os mesmos drivers que vimos para os browsers, porém trabalhando internamente, sem interface gráfica. Essa estratégia é muito usada por desenvolvedores ou testadores que querem criar scripts rapidamente sem ter de ficar acessando o browser o tempo todo.

Vamos criar um exemplo de acesso à página do Google e enviar uma palavra para ser pesquisada, dando submit no formulário e recebendo a resposta. Quando uma pesquisa é feita o título da página do Google muda de acordo com o texto, assim podemos recuperar essa nova informação e checar se o teste funcionou. Veja a Listagem 3 para isso.

Listagem 3. Código de teste para pesquisa no Google.

        package br.edu.devmedia.selenium;

        import java.util.concurrent.TimeUnit;

        import org.openqa.selenium.By;
        import org.openqa.selenium.JavascriptExecutor;
        import org.openqa.selenium.WebDriver;
        import org.openqa.selenium.WebElement;
        import org.openqa.selenium.htmlunit.HtmlUnitDriver;

        public class HTMLDriver {
        public static void main(String[] args) {
        WebDriver driver = new HtmlUnitDriver();

        driver.get("http://www.google.com");

        WebElement element = driver.findElement(By.name("q"));

        element.sendKeys("Queijo!");

        element.submit();

        System.out.println("O título da página é: " + driver.getTitle());

        driver.quit();
        }
        }
        

Agora é possível ver o acesso direto ao browser virtual do HTMLUnitDriver que também pode ser retornado para uma instância do WebDriver (linha 13). O método findElement() da linha 17 recupera o conteúdo HTML completo da página e faz uma busca pelo critério definido no se parâmetro que, por sua vez, será responsável por buscar um elemento único de nome “q” (no caso, a caixa de pesquisa da página do Google). Os critérios podem ser vários como por nome, id, classe CSS, etc.

O método sendKeys() na linha 19 envia o valor exatamente para o campo de input que deve ser preenchido antes do submit (linha 21) ser enviado. No final, extraímos o valor do atributo “title” do mesmo driver que já estará atualizado com a resposta.

Para conferir o resultado, execute a aplicação via comando Run e você verá algo parecido com o conteúdo da Listagem 4.

Listagem 4. Código de resultado da execução.

        ADVERTÊNCIA: CSS error: 'http://www.google.com.br/?gfe_rd=cr&ei=Z1h4VdzSMabX8gew3oHgAg' [1:9364] Error in
        expression; ':' found after identifier "progid".
        jun 10, 2015 12:31:42 PM com.gargoylesoftware.htmlunit.DefaultCssErrorHandler error
        [...]
        ADVERTÊNCIA: CSS error: 'http://www.google.com.br/?gfe_rd=cr&ei=Z1h4VdzSMabX8gew3oHgAg' [1:12791] Error in
        expression.
        (Invalid token ";". Was expecting one of: <S>, <NUMBER>, "inherit", <IDENT>, <STRING>,
        "-",
        <PLUS>, <HASH>, <EMS>, <EXS>,
        <LENGTH_PX>, <LENGTH_CM>, <LENGTH_MM>, <LENGTH_IN>, <LENGTH_PT>,
        <LENGTH_PC>,
        <ANGLE_DEG>,
        <ANGLE_RAD>, <ANGLE_GRAD>, <TIME_MS>, <TIME_S>, <FREQ_HZ>, <FREQ_KHZ>,
        <RESOLUTION_DPI>,
        <RESOLUTION_DPCM>, <PERCENTAGE>, <DIMENSION>, <URI>, <FUNCTION>.)
        [...]
        jun 10, 2015 12:31:42 PM com.gargoylesoftware.htmlunit.DefaultCssErrorHandler error
        ADVERTÊNCIA: CSS error: 'http://www.google.com.br/?gfe_rd=cr&ei=Z1h4VdzSMabX8gew3oHgAg' [1:15068] Error in
        pression; ':' found after identifier "progid".
        jun 10, 2015 12:31:42 PM com.gargoylesoftware.htmlunit.DefaultCssErrorHandler error
        [...]
        O título da página é: Queijo! - Pesquisa Google
        

Veja que no final da listagem temos a exibição do título da página. Nas linhas anteriores temos alguns erros exibidos (dentre outros que foram omitidos da listagem) que caracterizam o processo de validação do Selenium, ou seja, sempre que alguma tag não for fechada ou faltar algum atributo obrigatório ou tivermos qualquer erro a nível de HTML, essas linhas serão impressas. Mas não precisa se preocupar com isso, esse é um comportamento padrão do Selenium.

Em algumas situações será preciso também acessar propriedades via JavaScript de dentro das páginas. Por exemplo, suponha que em vez de acessarmos o título da página via método getTitle() do driver, nós quiséssemos executar um script JavaScript que fizesse o mesmo procedimento. Para isso, precisaríamos fazer uso da classe JavaScriptExecutor da API do Selenium e passar a string do nosso script como parâmetro para o seu método executeScript().

Entretanto, como em todo browser, também precisamos habilitar o seu suporte ao JavaScript. Os browsers comuns já vêm com ele habilitado, mas não é o caso do HTMLUnitDriver do Selenium. Vejamos o código da Listagem 5 para isso. Vamos acessar agora o site da DevMedia que tem mais recursos visuais para usarmos de exemplo.

Listagem 5. Código para busca de elementos via JavaScript.

        package br.edu.devmedia.selenium;

        import java.util.concurrent.TimeUnit;

        import org.openqa.selenium.By;
        import org.openqa.selenium.JavascriptExecutor;
        import org.openqa.selenium.WebDriver;
        import org.openqa.selenium.WebElement;
        import org.openqa.selenium.htmlunit.HtmlUnitDriver;

        public class HTMLDriver {
        public static void main(String[] args) {
        HtmlUnitDriver driver = new HtmlUnitDriver();
        driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
        driver.setJavascriptEnabled(true);

        driver.get("http://www.devmedia.com.br/");

        WebElement element = driver.findElementByCssSelector(".dm-busca");
        System.out.println("Cor de fundo: " + element.getCssValue("background-color"));
        System.out.println("Padding: " + element.getCssValue("padding"));
        System.out.println("Classe CSS:" + element.getAttribute("class"));

        JavascriptExecutor javascript = (JavascriptExecutor) driver;
        String tituloPagina = (String) javascript.executeScript("return document.title");
        System.out.println("O título da página é : " + tituloPagina);

        driver.quit();
        }
        }
        

Veja que na linha 14 estamos configurando um timeout para as requisições feitas ao HTMLUnitDriver. Isso porque os testes podem ser impactados quando um request demorar muito a retornar, logo você tem essa opção em mãos semelhante ao que fazemos com Web Services. O método implicityWait() define o tempo máximo de processamento, no caso cinco segundos.

Em seguida, na linha 15, usamos o método setJavascriptEnabled() para definir que o JavaScript estará habilitado nesse browser. Se estiver usando uma instância do Firefox ou Chrome como fizemos antes, esse código não será necessário.

Nas linhas seguintes vemos algumas propriedades novas, a saber:

  • Linha 19: O método findElementByCssSelector() recebe o seletor do elemento a ser recuperado na página HTML, no caso a caixa de pesquisas da página inicial; A Tabela 1 traz uma lista completa dos métodos possíveis.
  • Linhas 20 a 22: Imprimimos o valor das propriedades CSS de cor de fundo, padding e classe do mesmo elemento, respectivamente;
  • Linha 24: Instanciamos um novo objeto do tipo JavascriptExecutor a partir do próprio objeto driver (que o herda automaticamente pela herança de classes);
  • Linha 25: Chamamos o método executeScript() passando o JavaScript que queremos que seja executado no browser. Essa cláusula sempre deve vir precedida da palavra-chave “return”, já que precisamos que algo seja retornado;
  • Linha 28: Encerramos o driver.
Tabela 1. Lista de métodos para recuperar elementos no Selenium.
Estratégia Sintaxe Descrição
Por ID driver.findElement(By.id(<ID do elemento>)) Recupera um elemento pelo atributo “id”
Por nome driver.findElement(By.name(<Nome do elemento>)) Recupera um elemento pelo atributo “name”
Por nome da classe driver.findElement(By.className(<Classe CSS do elemento>)) Recupera um elemento pelo atributo “class”
Pelo nome da tag driver.findElement(By.tagName(<Nome da tag HTML>)) Recupera um elemento pelo nome da tag HTML
Pelo texto do link driver.findElement(By.linkText(<Texto do Link>)) Recupera um link usando seu texto.
Pelo texto parcial do link driver.findElement(By.partialLinkText(<Texto parcial do Link>)) Recupera um link pelo seu texto parcial
Por CSS driver.findElement(By.cssSelector(<Seletor do elemento>)) Recupera um elemento pelo seu seletor CSS
Por XPath driver.findElement(By.xpath(<expressão query xpath>)) Recupera um elemento usando um query XPath

Para verificar o resultado, reexecute a aplicação e você deverá ver no console a mensagem impressa pela Listagem 6.

Listagem 6. Mensagem final de execução do teste.

        Cor de fundo: rgb(48, 47, 49)
        Padding: 95px 0 45px 0
        Classe CSS:container-fluid dm-busca
        O título da página é: DevMedia - Tutoriais, Videos e Cursos de Programação
        

Agora suponha que precisamos migrar toda essa lógica de testes para o Firefox. Mais que isso, precisamos enviar apenas um texto de sugestão para a caixa de pesquisa do Google, mas sem clicar no submit. E após isso, esperar até que a caixa de sugestões apareça para que recuperemos todas as sugestões que o Google deu para a palavra informada. Vejamos como ficaria o nosso método main (Listagem 7).

Listagem 7. Teste caixa de sugestões do Google.

        package br.edu.devmedia.selenium;

        import java.util.concurrent.TimeUnit;

        import org.openqa.selenium.By;
        import org.openqa.selenium.JavascriptExecutor;
        import org.openqa.selenium.WebDriver;
        import org.openqa.selenium.WebElement;
        import org.openqa.selenium.htmlunit.HtmlUnitDriver;

        public class HTMLDriver {
        public static void main(String[] args) throws Exception {
        WebDriver driver = new FirefoxDriver();

        driver.get("http://www.google.com/webhp?complete=1&hl=en");

        WebElement query = driver.findElement(By.name("q"));
        query.sendKeys("devmedia");

        long end = System.currentTimeMillis() + 5000;
        while (System.currentTimeMillis() < end) {
        WebElement resultsDiv = driver.findElement(By.className("sbdd_b"));

        if (resultsDiv.isDisplayed()) {
        break;
        }
        }

        List<WebElement> allSuggestions = driver.findElements(By.xpath("//div[@class='sbqs_c']"));

        for (WebElement suggestion : allSuggestions) {
        System.out.println(suggestion.getText());
        }

        driver.quit();
        }
        }
        

Até a linha 18 fazemos a mesma configuração de recuperação do campo de pesquisa e informação da string a ser pesquisada. Na linha 20 criamos uma variável inteira com um valor cinco segundos à frente do tempo atual através do método currentTimeMillis(), assim teremos como pausar a execução do Selenium até que a página de sugestões seja gerada. O teste se baseia nos cinco segundos ou até que o objeto driver encontre o elemento de classe CSS “sbdd_b” que corresponde à respectiva caixa.

Uma vez encontrada (linha 24), recuperamos todos os elementos que casem com o xpath (expressão de caminho) da linha 29. Essa expressão diz que o driver tem de buscar por todos os elementos do tipo div que tenham classe CSS com valor “sbqs_c” que correspondem aos itens de sugestão.

No final, iteramos sobre essa lista (linha 31) e exibimos todos os seus valores (geralmente quatro). O interessante a se notar é que dessa vez acompanharemos a execução já que estamos executando via driver do Firefox.

Para ver o resultado, reexecute a aplicação e aguarde. Você deverá ver uma tela semelhante à da Figura 6 aparecer e fechar sozinha quando finalizar o teste, bem como o texto da Listagem 8 aparecer no console da IDE.

Tela de teste no Firefox com sugestões
Figura 6. Tela de teste no Firefox com sugestões.
Listagem 8. Mensagem final de execução do teste com sugestões impressas.

        >devmedia
        >devmedia cursos
        >devmedia player
        >devmedia java magazine
        >jun 10, 2015 1:04:47 PM org.openqa.selenium.os.UnixProcess$SeleniumWatchDog destroyHarder
        INFORMAÇÕES: Command failed to close cleanly. Destroying forcefully (v2).
        org.openqa.selenium.os.UnixProcess$SeleniumWatchDog@53aad5d
        

A mensagem final quer dizer que, uma vez que chamamos o método driver.quit() a instância do Firefox será finalizada.

Seletores jQuery

A biblioteca jQuery é extremamente mais simples e produtiva de usar em relação ao JavaScript puro. Você pode optar por usá-la em conjunto com seus seletores para recuperar elementos, definir eventos e funções de callback, bem como enviar submits em formulários.

Para criar um cenário mais próximo da realidade dos projetos, vamos criar uma página de cadastro de usuário simples com suporte a jQuery para os scripts e Bootstrap para o estilo e estrutura da mesma. Vejamos na Listagem 9 o código para isso.

Listagem 9. Código da página HTML de cadastro de usuários.

        <!DOCTYPE html>
        <html lang="en">
        <head>
        <title>Selenium Teste</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
        </head>
        <body>

        <div class="container">
        <div class="col-md-12">
        <h2>Cadastro de Pessoa</h2>
        <div class="panel panel-info">
        <div class="panel-heading">Formulário Básico</div>
        <div class="panel-body">
        <form role="form">
        <div class="form-group">
        <label class="control-label" for="exampleInputEmail1">Email</label>
        <input type="email" class="form-control" id="exampleInputEmail1" placeholder="Digite seu email">
        </div>

        <div class="form-group">
        <label class="control-label" for="exampleInputPassword1">Password</label>
        <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Digite sua senha">
        </div>

        <div class="form-group">
        <div class="checkbox">
        <label> <input type="checkbox"> Ativo </label>
        </div>
        <p class="help-block">Lorem ipsum dolor sit amet</p>
        </div>

        <div class="form-group">
        <label class="control-label">Opções</label>
        <div class="checkbox">
        <label> <input type="checkbox" name="optionsRadios" id="optionsCheckbox1" value="option1"
        ecked="">
        ção 1 </label>
        </div>
        <div class="checkbox">
        <label> <input type="checkbox" name="optionsRadios" id="optionsCheckbox2" value="option2"> Opção
        2
        </label> </div>
        </div>

        <div class="form-group">
        <label class="control-label">Sexo</label>
        <div class="radio">
        <label> <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked="">
        Masculino </label>
        </div>
        <div class="radio">
        <label> <input type="radio" name="optionsRadios" id="optionsRadios2" value="option2"> Feminino
        </label>
        </div>
        </div>

        <button type="submit" class="btn btn-default">Criar Usuário</button>
        </form>
        </div>
        </div>
        </div>
        </div>
        </body>
        </html>
        

A listagem faz a importação no início dos arquivos de script necessários para carregar o jQuery e o estilo do Bootstrap (linhas 7 a 9). Os imports foram feitos via CDN (Content Delivery Network) portanto, não precisamos baixá-los estaticamente. A página traz apenas dois campos de input (email e senha, linhas 22 e 32), três checkboxes, dois botões de rádio e o botão de submit no fim da mesma. Você pode visualizar a página executando o arquivo diretamente no browser, tal como mostrado na Figura 7.

Tela de cadastro de usuários para teste
Figura 7. Tela de cadastro de usuários para teste.

Nossos objetivos com esta página serão (Listagem 10):

  • Buscar todos os elementos checked e exibir a quantidade;
  • Buscar o id do elemento que recebeu o foco (email);
  • Mudar a seleção do campo sexo para feminino;
  • Mudar o texto do botão de submit para “Texto Mudado”.
Listagem 10. Código para acessar propriedades da página de cadastro.

        package br.edu.devmedia.selenium;

        import java.util.concurrent.TimeUnit;

        import org.openqa.selenium.By;
        import org.openqa.selenium.JavascriptExecutor;
        import org.openqa.selenium.WebDriver;
        import org.openqa.selenium.WebElement;
        import org.openqa.selenium.htmlunit.HtmlUnitDriver;

        public class HTMLDriver {
        public static void main(String[] args) {
        WebDriver driver = new FirefoxDriver();
        driver.get("file:///D:/Downloads/login.html");

        List<String> checked = Arrays.asList(new String[]{"optionsCheckbox1", "optionsRadios1"});
        JavascriptExecutor js = (JavascriptExecutor) driver;

        @SuppressWarnings("unchecked")
        List<WebElement> checkedElements = (List<WebElement>) js.executeScript("return
        jQuery.find(':checked')");

        @SuppressWarnings("unchecked")
        List<WebElement> focusElements = (List<WebElement>) js.executeScript("return
        jQuery.find(':focus')");

        if (checkedElements.size() == 2)
        System.out.println("Duas checkboxes selecionadas");

        if (focusElements.size() == 1)
        System.out.println("Campo com foco: " + focusElements.get(0).getAttribute("id"));

        for (WebElement element : checkedElements) {
        if (checked.contains(element.getAttribute("id"))) {
        System.out.println("Elemento contém id");
        }
        }

        js.executeScript("jQuery('#optionsRadios2').attr('checked', 'checked')");
        js.executeScript("jQuery('button[type=\"submit\"]').text('Texto Mudado')");

        // driver.close();
        }
        }
        

A primeira mudança significativa está na linha 14, onde estamos acessando o arquivo HTML localmente, diretamente da pasta onde você salvou a página. Dessa forma não precisamos hospedar a aplicação para fazer os testes e o Selenium provê esse recurso de maneira off-line. Na linha 16 criamos uma lista de WebElement’s para recuperar todos os itens checados (rádio e checkbox) da página. Veja que é nesse trecho onde executamos o primeiro código jQuery que precisa ter o seletor informado dentro método executeScript().

Na linha 23 fazemos a mesma seleção, só que agora para o campo que tem o foco (:focus). Na linha 25 testamos o tamanho da lista de elementos checados e na linha 28 para a lista de elementos com foco. Da linha 31 a 35 verificamos se algum dos elementos recuperados contém o atributo “id”, apenas para imprimir a mensagem de sucesso.

No final, na linha 37 executamos o código jQuery para selecionar o rádio de Feminino, e na linha 38 mudamos o texto do botão de submit.

Para verificar o resultado, reexecute a aplicação e você verá algo semelhante ao que temos na Figuras 8 (no browser Firefox) e 9 (no console da IDE).

Tela de cadastro de usuários após o teste
Figura 8. Tela de cadastro de usuários após o teste.
Tela de console com resultado da execução
Figura 9. Tela de console com resultado da execução.

O leitor ainda pode adicionar mais arquivos de scripts ou CSS dinamicamente a partir do código Selenium via variável var headID que está disponível para representar o cabeçalho da página. Isso vale, inclusive, para quaisquer frameworks jQuery que queira acrescentar na implementação.

Selenium IDE na prática

A Selenium IDE é uma ferramenta de testes para aplicações web totalmente integrada com os conceitos do framework no que se refere à gravação e playback dos testes de regressão. Através dela, o desenvolvedor não é mais obrigado a usar qualquer linguagem de programação, apesar de poder fazer isso. Também é possível exportar os scripts para quaisquer linguagens suportadas.

Os scripts criados para a aplicação de teste são chamados de casos de teste e um conjunto de casos de teste é chamado de suíte. Para trabalhar com ela, é preciso primeiro fazer o download (seção Links). Efetue o download da versão mais recente na subseção “Selenium IDE” e dê um click duplo para iniciar a instalação.

É importante que o leitor considere que essa IDE só é suportada pelo Firefox, logo não é possível configurá-la em outros browsers (caso prefira o Chrome, use a opção com Java mostrada na seção anterior). Reinicie o Firefox e pronto, sua IDE está instalada. Para verificar, vá até a opção “Tools > Selenium IDE” e uma janela igual à da Figura 10 irá aparecer.

Janela da Selenium IDE no Firefox
Figura 10. Janela da Selenium IDE no Firefox.

Na Tabela 2 você pode encontrar um detalhamento dos principais botões e funcionalidades fornecidos pela IDE.

Tabela 2. Lista de botões e comandos padrão da Selenium IDE.
Botão Descrição
Controlador de Velocidade
Controlador de Velocidade
É usado para controlar o quão rápidos seus casos de teste irão executar.
Botão “Run All”
Botão Run All
É usado para executar a suíte de testes completa, com todos os testes adicionados a ela. A execução ocorre na ordem em que os testes forem declarados.
Botões “Pause/Resume”
Botão Pause
Botão Resume
O primeiro botão pausa a execução do teste atual, enquanto o segundo retoma-a.
Botão “Step”
Botão Step
É usado para executar os comandos de teste um por um, manualmente. Suponha que você tenha pausado o teste e agora deseja ver linha por linha o que está acontecendo.... Esse botão faz isso, simulando um debug comum.
Botões “Record/Stop Recording”
Botão Record
Botão Stop recording
O primeiro é usado para iniciar a gravação de um script e o segundo para encerrá-la.
Botão “Toggle Schedule”
Toggle Schedule
É usado para agendar execuções de script. Serve para situações onde o software precisa rodar um teste de tempos em tempos, sem a necessidade de um humano por perto.
Janela “Table”
Janela Table
Exibe os comandos gravados. Você pode modificar e incluir novos comandos, que são divididos em três partes:
  1. Command: descreve o nome do comando;
  2. Target: descreve o elemento alvo (id ou name) do Xpath;
  3. Value: descreve o valor do elemento.

Primeiros testes na IDE

Agora que temos a IDE instalada, podemos gravar um teste automatizado apenas usando a aplicação desejada normalmente. Façamos um teste com os seguintes passos:

  1. Entrar no site da DevMedia.
  2. Clicar no botão “Login”.
  3. Digitar um login e senha qualquer.
  4. Clicar em “OK”.

O teste é demasiadamente simples, mas é o suficiente para que você entenda como o Selenium salva seus scripts. Agora, abra uma nova aba do browser (em branco) e na IDE clique no botão “Record”. Em seguida, efetue a lista de passos que mostramos e ao finalizar, clique no botão “Stop Recording”.

Ao final, sua IDE estará semelhante à que temos na Figura 11. Veja que temos cinco comandos com tipos e targets diferentes. Por exemplo: o tipo “open” define que entramos numa URL (exibida no topo da janela, no campo “Base URL”); o tipo “click” define que clicamos num elemento de nome “usuario” e o tipo “clickAndWait” define que foi enviado um submit e que o Selenium deve aguardar até que a resposta retorne. Em relação aos campos que precisam de um valor a ser informado (input text), a terceira coluna é preenchida com os mesmos.

Selenium IDE com testes finalizados e gravados
Figura 11. Selenium IDE com testes finalizados e gravados.

Você também pode modificar os seus testes via script. Clique na aba “Source” ao lado de “Table” e você verá um conteúdo semelhante ao da Listagem 11.

Listagem 11. Código script gerado para o teste na Selenium IDE.

        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        <head profile="http://selenium-ide.openqa.org/profiles/test-case">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link rel="selenium.base" href="http://www.devmedia.com.br/" />
        <title>New Test</title>
        </head>
        <body>
        <table cellpadding="1" cellspacing="1" border="1">
        <thead>
        <tr><td rowspan="1" colspan="3">New Test</td></tr>
        </thead><tbody>
        <tr>
        <td>open</td>
        <td>/</td>
        <td></td>
        </tr>
        <tr>
        <td>click</td>
        <td>css=div.popover1</td>
        <td></td>
        </tr>
        <tr>
        <td>type</td>
        <td>name=usuario</td>
        <td>test</td>
        </tr>
        <tr>
        <td>type</td>
        <td>name=senha</td>
        <td>123</td>
        </tr>
        <tr>
        <td>clickAndWait</td>
        <td>css=button[type="submit"]</td>
        <td></td>
        </tr>

        </tbody></table>
        </body>
        </html>
        

O conteúdo do script é sempre gerado em HTML, logo temos as importações das tags meta e link na tag head, bem como a tabela com os comandos logo abaixo. É aconselhável que o leitor sempre utilize a opção gráfica para evitar qualquer erro de sintaxe na ferramenta.

Agora, sempre que quiser reexecutar o mesmo teste, basta selecionar o nome do test case na barra lateral esquerda e clicar no botão “Play test suite”.

Sobre os Casos de Teste

A primeira vez que abrimos a IDE do Selenium o botão de gravação já vem ativado, e isso permite uma interação via uso do site que terá seus scripts salvos. Se você não deseja que a IDE faça isso, vá até o menu “Options > Options...” e desmarque a opção “Start recording immediately on open”.

Quando se está construindo um caso de testes, algumas considerações devem ser levadas em conta:

  • Para gravar ações do tipo submit, é necessário que o usuário clique no botão em vez de dar um enter em algum dos campos do formulário. Isso porque o Selenium não consegue reconhecer esse evento e associar a um envio de request, já que o usuário pode dar vários enters, ou ter um controle de navegação de campo para campo via tecla Enter, em vez de Tab.
  • Quando clicamos em um link durante uma gravação, o Selenium IDE grava o comando no tipo “click”. Porém, você deve mudar esse tipo para “clickAndWait” para garantir que o seu caso de teste fará uma pausa até que a página carregue por completo e o fluxo possa prosseguir sem erros. Caso contrário, nosso caso de teste continuará executando os comandos antes que a página tenha todos os elementos UI carregados na HTML.

Os seus casos de teste também terão que verificar as propriedades de uma página da web. Isso requer o uso dos comandos assert (comparar dois valores) e verify (fazer um teste qualquer). Quando o Selenium IDE estiver gravando, vá até o navegador exibindo seu aplicativo de teste e clique com o botão direito em qualquer lugar da página. Será exibido um menu de contexto mostrando os referidos comandos bem como outros (Figura 12) que podem ser usados via Selenium.

Menu de contexto com comandos Selenium
Figura 12. Menu de contexto com comandos Selenium.

A primeira vez que você acessar a IDE, terá apenas um ou dois comandos disponíveis. Mas à medida que for criando seus casos de teste e o browser for efetuando operações mais complexas, como submits, scrolling, dentre outras, o Selenium irá preenchendo essa lista automaticamente com as opções que ela julgar que você possa precisar. Dentre a lista de comandos mostrada na figura, os principais são:

  • open: abre uma página usando a URL passada;
  • click/clickAndWait: executa uma operação de clique e, opcionalmente, aguarda uma nova página carregar;
  • verifyTitle/assertTitle: verifica se um título esperado para a página está presente;
  • verifyTextPresent: verifica se um texto esperado está em algum lugar na página;
  • verifyElementPresent: verifica se um elemento UI esperado, tal como definido pela sua tag HTML, está presente na página;
  • verifyText: verifica se o texto esperado e sua tag HTML correspondente estão presentes na página;
  • verifyTable: verifica se conteúdo esperado de uma tabela está presente;
  • waitForPageToLoad: finaliza a execução até que uma nova página seja carregada. Chamado automaticamente quando o clickAndWait é usado;
  • waitForElementPresent: finaliza a execução até que um elemento da interface do usuário esperado, conforme definido pela sua tag HTML, está presente na página.

Existem inúmeras outras abordagens nas quais o leitor poderá usar o Selenium. Como vimos, a automação precisa estar obrigatoriamente vinculada a telas, estejam elas executando num PC, smartphone, tablet, etc. O Selenium conta ainda com dois drivers específicos para ambientes móveis: AndroidDriver, classe da API do Selenium exclusiva para dispositivos Android; e iWebDriver, para simular testes em ambiente iOS.

Também é possível integrar o Selenium com o JUnit, QUnit, JTestDriver e outros inúmeros frameworks de teste unitário disponíveis no mercado. Os arquivos que eles geram em conjunto são leves e podem facilmente se adaptar a um controle de integração com o Jenkins, por exemplo, bem como ser manuseados por ferramentas de versionamento (Git, Mercurial, etc.).

Para os desenvolvedores PHP que querem fazer uso do Selenium, o mesmo não provê suporte nativo à linguagem, mas é possível usar o PHPUnit: uma instância do xUnit para testes unitários que traz consigo módulos do Selenium que podem ser instalados via linha de comando.

Confira também