Posts com a tag ‘webdriver’

Selenium 2.0, o que muda com essa nova versão?

14 de setembro de 2010

Olá pessoal,

Já queria falar sobre esse assunto há um bom tempo, mas fiquei enrolando e finalmente chegou a hora.

Para quem ainda não sabe, o Selenium passará (já passa, está em alpha) por uma grande evolução.

O Selenium 2.0 é um merge entre o Selenium e o Webdriver.
Para quem não sabe, o Webdriver é um projeto criado pelo Google para fazer a mesma coisa que o Selenium faz, mas com algumas melhorias:
1. Uma API voltada para desenvolvedores.
2. Consistência entre os browsers.
3. Corrigir funcionalidades mal suportadas pelo Selenium 1.0.

Para explicar o que realmente muda, nada melhor do que exemplos.

Temos a seguinte página mostrando uma tabela com produtos. O nosso teste é verificar se os produtos estão aparecendo corretamente.

<html>
<body>
 <table border="1">
  <tbody>
   <tr>
    <td>Produto 1</td>
    <td>Produto 2</td>
    <td>Produto 3</td>
   </tr>
  </tbody>
 </table>
</body>
</html>

Vamos criar um projeto do zero no maven usando Selenium2. Se você usa outra linguagem, ou não conhece o maven, não se preocupe, pois você vai conseguir entender praticamente tudo.

Crie o projeto com o seguinte comando:

mvn archetype:create -DgroupId=seuenium -DartifactId=exemplo-se2

Agora vamos editar o arquivo pom gerado em exempo-se2/pom.xml.
Acrescente a dependência para o Selenium2:

<dependency>
  <groupId>org.seleniumhq.selenium</groupId>
  <artifactId>selenium</artifactId>
  <version>2.0a5</version>
</dependency>

Agora vamos criar um teste usando a nova API. Crie a classe src/test/java/seuenium/ExemploTest.java.
Em seguida, vamos criar o método anotado com @Before inicializando o Selenium. Vai ficar mais ou menos assim:

public class ExemploTest
{
    private FirefoxDriver driver;
 
    @Before
    public void before() {
        this.driver = new FirefoxDriver();
    }
}

Aí está a primeira mudança. Antes você tinha que instanciar a classe DefaultSelenium passando o ip do selenium-server, a porta, o browser e a url base e ainda por cima dar chamar o comando start(). Agora você só precisa instanciar a implementação do browser que você quer.
E aí você me pergunta: onde ficam as configurações do servidor e porta?
Aí está outra grande mudança. A API agora conversa diretamente com o browser e você não precisa de um servidor em pé para fazer essa tarefa pra você.
Mas isso é opcional. Você pode continuar com um selenium-server rodando e seus testes devem usar uma instância de RemoteWebDriver. Mas isso é assunto para outro post.

Agora vamos criar o nosso teste que consiste em validar que todos os produtos estão aparecendo na tabela. Crie um método testSucesso anotado com @Test.

O primeiro passo é abrir a URL. Antes usávamos o comando open, agora usa o comando get:

driver.get( "http://www.seuenium.com.br/testes/12-se2/index.html" );

Em seguida vamos validar o texto do primeiro produto da tabela. No Se1, você usaria o seguinte comando:

assertEquals("Produto 1", selenium.getText("//table//tr/td[1]"));

Agora não tem mais convenção nos locators, você tem que chamar o método específico de como você quer localizar os elementos. Exemplo:

assertEquals("Produto 1", driver.findElementByXPath( "//table//tr/td[1]" ).getText());

ou

assertEquals("Produto 1", driver.findElement( By.xpath( "//table//tr/td[1]" ) ).getText());

Note que os métodos findElement* retornam o objeto WebElement, e nele contém outros métodos para pegar o texto, algum atributo e/ou valor.

Agora vamos testar se os outros produtos da tabela estão corretos.
No Se1, você faria algo assim:

assertEquals("Produto 1", selenium.getText("//table//tr/td[1]"));
assertEquals("Produto 2", selenium.getText("//table//tr/td[2]"));
assertEquals("Produto 3", selenium.getText("//table//tr/td[3]"));

No Se2 há um jeito melhor de fazer isso:

List<WebElement> elements = driver.findElements( By.xpath( "//table//tr/td" ) );
assertEquals("Produto 1", elements.get( 0 ).getText());
assertEquals("Produto 2", elements.get( 1 ).getText());
assertEquals("Produto 3", elements.get( 2 ).getText());

Note que o método findElements retorna uma lista dos elementos encontrados, facilitando o teste.

Outro ponto interessante é que para cada objeto WebElement você também pode chamar os métodos findElement*. Quando isso acontece, o Se2 vai procurar por elementos filhos do elemento atual. Isso sim é uma API voltada para desenvolvedores. Acredito que isso vai facilitar muito, e muita gente vai aposentar de vez o XPath.
No nosso exemplo, se eu não quisesse usar Xpath, poderia usar algo assim:

List<WebElement> elements = driver.findElement( By.tagName( "table" ) ).findElements( By.tagName( "td" ) );
        assertEquals("Produto 1", elements.get( 0 ).getText());
        assertEquals("Produto 2", elements.get( 1 ).getText());
        assertEquals("Produto 3", elements.get( 2 ).getText());

Note que usei o locator By.tagName que busca pelo nome dos elementos. Outros locators disponíveis são: By.className( className ), By.cssSelector( selector ), By.id( id ), By.linkText( linkText ), By.name( name ), By.partialLinkText( linkText ), By.tagName( name ), By.xpath( xpathExpression ).

Outro método que precisa ser criado é o método para finalizar o Selenium. Antes era o comando stop(). Agora é o quit:

@After
public void tearDown() {
    this.driver.quit();
}

Bom, é isso galera. O exemplo você pode baixar aqui.
Ainda tem muito mais coisa a falar do Selenium 2.0 e pretendo criar outros posts para isso, mas já vimos que as mudanças da nova API vieram para ajudar ainda mais o desenvolimento dos testes. Isso prova cada vez mais que teste automatizado não é só ficar clicando e esperando que alguma ferramenta grave pra você, tem que por a mão na massa. Quem quiser ler mais sobre o Se2, acesse esse link do site oficial.

Valeu pessoal!!!