Começa hoje a venda dos tickets para a SeleniumConf

1 de fevereiro de 2011 por Enium

Isso mesmo galera. Hoje começa a venda das inscrições. Opa, peraí, já começou. Enquanto estou escrevendo esse post foi liberado o primeiro lote dos ingressos, e a boa notícia é que eles são $40 dólares mais baratos que o normal. Corra e garanta já o seu, porque são apenas 50 ingressos com desconto -> http://www.seleniumconf.com/tickets/
Minha ideia é fazer um post pra cada palestra que ver lá, assim quem não for vai poder acompanhar pelo Blog do Seu Enium o que tá rolando por lá.
Nos vemos em San Francisco.
Bye bye!!!

Atualização: os ingressos com desconto acabaram praticamente no mesmo dia. Agora só restam os com valor de US$235

SeleniumConf – A primeira conferência sobre Selenium

7 de dezembro de 2010 por Enium

É isso aí pessoal.

Ano que vem, 2011, entre os dias 4 e 6 de abril, lá em San Francisco – California, será realizada a primeira conferência oficial e exclusiva sobre Selenium.

Serão 3 dias de pura automação. Duas trilhas ao mesmo tempo e sessões paralelas para você colocar a mão na massa. Você terá a oportunidade de conhecer desenvolvedores, usuários e entusiastas do Selenium que estão ao redor desse mundo.

As inscrições poderão ser feitas a partir do dia 28 de Janeiro de 2011 pelo site www.seleniumconf.com.

O valor da inscrição é de $235, o que dá uns R$400. É carinho né, e ainda por cima tem que contar com voo e hospedagem.

Mas se você estiver realmente disposto a ir, fique atento porque são apenas 250 vagas.

Além do site você pode seguir o twitter @seleniumconf para receber atualizações sobre a conferência.

Nos vemos lá!!!

O enésimo elemento em Xpath

6 de outubro de 2010 por Enium

Cada dia aprendo uma coisa nova e surpreendente.
Estava eu lendo o “A Smattering of Selenium” do blog oficial do Selenium, que por sinal é muito bom para ficar antenado sobre as notícias do Selenium, e encontrei um post que fala justamente de um problema que comentei recentemente no blog, o problema do enésimo elemento.
Até então eu pensava que a única solução nativa era trabalhar com os índices dos elementos pais, mas há outras duas maneiras de resolver o problema.

Problema: dado abaixo um exemplo em html, quero verificar que o texto da quarta célula da tabela é “Produto 4″
Exemplo:

 <table>
   <tr>
    <td>Produto 1</td>
    <td>Produto 2</td>
    <td>Produto 3</td>
   </tr>
   <tr>
    <td>Produto 4</td>
    <td>Produto 5</td>
    <td>Produto 6</td>
   </tr>
 </table>

Solução 1: assertText | //tr[2]/td[1] | Produto 4
Explicação 1: essa é a solução simples onde você tem que trabalhar com o índice do elemento pai, no nosso caso o elemento tr.

Solução 2: assertText | xpath=/descendant::td[4] | Produto 4
Explicação 2: você deve trocar o // pela função descendant do xpath. A anotação // de xpath, corresponde à função descendant-or-self que para quando acha o primeiro elemento. Note que tem que forçar o xpath= já que você não vai usar o //. Você pode ler mais sobre isso aqui.

Solução 3: assertText | xpath=(//td)[4] | Produto 4
Explicação 3: essa solução só funciona com o Selenium, não é nativo do xpath. Você explicita que está usando xpath, coloca sua expressão em parênteses e em seguinda coloca o índice do elemento desejado.

Vivendo e aprendendo!!! To pensando em mudar o nome do blog para O Blog do Seu Enésimo :)
Até a próxima.

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

14 de setembro de 2010 por Enium

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!!!

JQuery Selectors no Selenium

3 de setembro de 2010 por Enium

Já expliquei aqui no blog quais são as diversas maneiras de selecionar os elementos da página com o Selenium. Mas em alguns casos, as expressões em Xpath ou CSS do Selenium ficam complicadas de serem montadas.

Vou dar um exemplo bom de quando isso acontece.

Temos a seguinte tabela em html:

<table>
	<tr>
		<td>Produto 1</td>
		<td>Produto 2</td>
		<td>Produto 3</td>
	</tr>
	<tr>
		<td>Produto 4</td>
		<td>Produto 5</td>
		<td>Produto 6</td>
	</tr>
</table>

Agora queremos validar o texto da quarta célula que é “Produto 4″.

Em Xpath, a primeira tentativa seria:

assertText | //td[4] | Produto 4

Porém isso não funciona. Como a quarta célula está na segunda linha da tabela, você tem que entrar primeiro na linha correta e usar índice 1 no td . Exemplo:

assertText | //tr[2]/td[1] | Produto 4

O mesmo ocorre com css locator.
Não funciona:

css=td:nth-child(4)

Funciona:

css=tr:nth-child(2) td:nth-child(1)

Não seria mais fácil se não precisasse usar o índice da linha?
Para isso, você terá que extender o Selenium com Jquery/Sizzle.

Por baixo dos panos o JQuery usa o Sizzle, que é uma implementação em Javascript de seletores CSS. Antigamente essa engine de css ficava dentro do próprio JQuery, mas ela foi separada para que evoluisse de forma independente.

Vou exemplificar passo a passo como configurar o Selenium IDE para usar o Sizzle:

1. Acesse http://sizzlejs.com e faça o download do arquivo zip.
2. Extraia o arquivo sizzle.js para algum diretório de sua preferência.
3. Renomeie o arquivo sizzle.js para user-extensions.js
4. Edite o final do arquivo acrescentando:

function eval_css(locator, inDocument) {
    var results = [];
    window.Sizzle(locator, inDocument, results);
    return results;
}

5. Abra a IDE e acesse Option -> Option e em Selenium Core extensions, coloque o path do arquivo editado.
6. Feche a IDE e abre-a de novo.
7. Pronto, os locators em css serão interpretados pelo Sizzle!!!

Para quem usa o Selenium RC, é só subir o selenium-server com o parâmetro “-userExtensions user-extensions.js”.

Voltando ao nosso exemplo, o comando abaixo funcionaria perfeitamente, usando apenas um índice:

assertText | css=td:eq(3) | Produto 4

Usamos o selector “eq” que faz exatamente o que precisamos. Note que o índice no Sizzle começa em 0 enquanto que no Selenium começa em 1.

Há outras funções que podem ser usadas. Dê uma olhada na documentação do Sizzle.

A boa notícia é que o Selenium irá trocar a api atual (cssQuery) que interpreta CSS locators para usar o Sizzle. Então na próxima versão, você não precisará mais alterar o user-extensions.js para sobrescrever o comportamento dos locators css.

Perguntas e Respostas sobre Selenium

25 de agosto de 2010 por Enium

Para quem não conhece, foi criada uma área no StackExchange dedicada 100% ao Selenium. É um site de perguntas e respostas, e o grande lance é que geralmente as perguntas e respostas são de alta qualidade, já que muito expert no assunto participa.
O site ainda está na fase de commitment, e isso quer dizer que precisa atingir um certo número de usuários comprometidos a fazer perguntas e respostas para passar para a próxima fase. Quando isso acontecer, o site finalmente será liberado para perguntas e respostas. Hoje a taxa de commitment está em 22%, precisamos chegar nos 100%.
Se você acho o Selenium muito legal e tem interesse em contribuir para a comunidade, inscreva-se agora!!
http://area51.stackexchange.com/proposals/4693/selenium

O único problema é que o site é em inglês. Se você não se sente confortável em ler e escrever em inglês, tire suas dúvidas em português na parte de Dúvidas do blog.

Ajude a divulgar essa ideia!!!

Autenticação HTTP básica e Selenium

14 de maio de 2010 por Enium

Recentemente, um dos leitores do blog me perguntou como automatizar um teste quando o sistema tem uma autenticação HTTP básica e achei interessante compartilhar com vocês.

Exemplo de autenticação HTTP básica

Não há nada específico para o Selenium, mas sim sobre o protocolo HTTP.
Segundo a RFC 1738 que descreve como devem ser escritas as URLs, você pode definir o usuário e senha diretamente no endereço que deseja acessar. Exemplo:

http://usuario:senha@www.seusite.com/home.html

Aparentemente, isso deveria funcionar para todos os browsers, já que é um padrão. Mas no Internet Explorer não vai funcionar. Isso porque o Windows desabilita essa autenticação por medidas de segurança. Mas como para testar no IE você tem que subir o Selenium Remote Control, isso não será um problema já que o próprio RC altera o registro do Windows habilitando essa funcionalidade. Para maiores informações você pode dar uma olhada aqui.

Portanto, no seu teste automatizado, você teria que usar o comando open e alterar a URL desejada para conter os dados de acesso:

open | http://usuario:senha@www.seusite.com/home.html

Até a próxima :)

Screenshot com Selenium – Parte 2, TestNG

23 de abril de 2010 por Enium

Há um tempo atrás escrevi um post demonstrando como dar print screen com Junit, Maven e Selenium se houvesse algum erro no teste.
Recentemente, um dos leitores do blog me perguntou se era possível fazer o mesmo só que usando o TestNG.
Como eu não uso muito o TestNG, eu não sabia se isso era possível, e fui atrás da documentação do TestNG e a do plugin Surefire do maven.

Para fazer isso, você terá que extender a classe TestListenerAdapter e implementar o método onTestFailure que será invocado após qualquer exceção disparada.

Deve ficar mais ou menos assim:

import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
import com.thoughtworks.selenium.DefaultSelenium;
 
public class ScreenshotListener extends TestListenerAdapter
{
 
    public void onTestFailure(ITestResult result)
    {        
        try {
 
            AbstractTestCase testCase = (AbstractTestCase) result.getTestClass().getInstances(false)[0];
 
            DefaultSelenium selenium = testCase.getSelenium();
            if (selenium != null) {
                String fileName = System.getProperty(
                        "screenshots.dir", "/tmp")
                        + "/" + result.getTestClass().getName() + "-" + result.getName() + ".png";
                System.out.println("Capturando erro em: " + fileName);
                selenium.captureEntirePageScreenshot(fileName, "background=#FFFFFF");
            }
 
        } catch (Exception e2) {
            System.err
                    .println("Não foi possível capturar o screenshot");
        }
    }
}

Outro passo necessário é configurar o plugin surefire e informar o listener a ser usado:

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-surefire-plugin</artifactId>
	<configuration>
		<properties>
			<property>
				<name>listener</name>
				<value>br.com.seuenium.ScreenshotListener</value>
			</property>
		</properties>
	</configuration>
</plugin>

Pronto.

Que tal integrar esse código com o exemplo de paralelização em testes do Selenium com TestNG descritos nesse post?

Como eu sou bonzinho, já deixei isso pronto. Pode baixar o exemplo AQUI e depois rode o comando mvn clean install.

Até a próxima.

Testes unitários com EasyMock e JUnit – Introdução

13 de abril de 2010 por leandro

A partir de agora, o Blog do Seu Enium terá a participação de um novo colaborador. Seu nome é Leandro, mais conhecido como Mendigo, e trabalhamos juntos no UOL.

Para iniciar a participação dele no blog, ele vai falar um pouco sobre uma biblioteca que auxilia bastante na hora de efetuar testes unitários com java: EasyMock.

Esta biblioteca permite que nós criemos objetos de um determinado tipo (classe ou interface), para podermos isolar a classe a ser testada.

Mas por que fazer isso? Bom, quando estamos testando de forma unitária, é interessante que foquemos somente na classe, ou mesmo somente em um método da classe. Porém, em um projeto orientado à objetos, o que temos, idealmente, é um conjunto de classes efetuando tarefas específicas e interagindo entre si. A grande maioria das classes possui dependências em relação à outras classes. É importante que o grau de dependência (ou acoplamento) seja baixo, para que alterações em dependências não afetem drasticamente a classe dependente, mas esse acoplamento dificilmente será zero (nesse caso teríamos uma classe inchada, fazendo muita coisa, e difícil de manter).

Por exemplo, vamos considerar uma classe que leia informações de uma fonte de entrada, e escreva informações em um destino. Além disso, essa classe é capaz de interpretar alguns comandos básicos para manipular os dados de entrada (neste primeiro exemplo a classe sabe somente enviar a hora atual).

(o código do exemplo está disponível aqui)

Processor

package foo;
 
public class Processor
{
 
   private Source source;
   private Destination destination;
 
   public Processor( Source source, Destination destination ) {
      this.source = source;
      this.destination = destination;
   }
 
   public void process() {
      String input = null;
      try
      {
         input = source.read();
      }
      catch (Exception e)
      {
 
      }
 
      if( input != null ) {
         String output = transform( input );
 
         try
         {
            destination.write( output );
         }
         catch (Exception e)
         {
            throw new ProcessorException("Nao foi possível enviar os dados");
         }
      }
   }
 
   private String transform(String input)
   {
      if( "[[Time]]".equals( input ) ) {
         return "time: " + System.currentTimeMillis();
      }
      return input;
   }
}

Source

package foo;
 
public interface Source
{
 
   String read();
 
}

Destination

package foo;
 
public interface Destination
{
 
   void write(String output);
 
}

Para complicar um pouco, vamos considerar que Source obtém os dados de um banco de dados e que Destination envia os dados escritos pela rede. Dessa foram para testarmos a classe Processor, seria necessário acessar um banco de dados e enviar dados pela rede.

Em testes de integração ou de sistema, isso está OK, mas em testes de unidade não. Estes deveriam ser isolados, contidos, não condicionados à disponibilidade ou não dos recursos externos como rede ou banco. Além disso, eles deveriam rodar de forma muito rápida, para não atrasar o processo de build e de desenvolvimento.

Com o EasyMock podemos criar um objeto que se passe por um Source, mas que não acessa realmente o banco de dados, e um outro que emule o comportamento de um Destination, sem efetivamente enviar dados pela rede, isolando assim a nossa “unidade” (Processor) e tendo um controle total sobre os mocks (Neste post estou chamando tudo de mock, porém há algumas implicações “técnicas” nesta nomenclatura, e para quem quiser se aprofundar melhor, sugiro este texto: http://martinfowler.com/articles/mocksArentStubs.html)

Vamos escrever um teste para o fluxo mais básico do nosso Processor.

package foo;
 
import org.easymock.EasyMock;
import org.junit.Test;
 
public class ProcessorTest
{
 
   @Test
   public void testProcess()
   {
      // Criação dos mocks e configurando o comportamento esperado
      Source source = EasyMock.createMock(Source.class);
      Destination destination = EasyMock.createMock(Destination.class);
 
      EasyMock.expect(source.read()).andReturn("SeuEnium");
      destination.write("SeuEnium");
 
      EasyMock.replay(source, destination);
 
      // Testando a nossa "unidade"
      Processor processor = new Processor(source, destination);
 
      processor.process();
 
      // Verificando o comportamento
      EasyMock.verify(source, destination);
   }
 
}

Neste teste podemos ver um esquema básico de utilização de mocks:

    1. Criação dos mocks – a forma mais simples é a ilustrada no exemplo: EasyMock.createMock( Source.class )
      Este método irá criar um mock do tipo especificado (Classe ou Interface) – O EasyMock é capaz de criar mocks tanto de classes quanto de interfaces (neste exemplo vamos lidar somente com interfaces)
      Comportamento esperado – os mocks são criados em um estado de gravação – tudo o que for feito com o objeto até a chamada de EasyMock.replay( source ) será gravado internamente pelo EasyMock, e esse comportamento será depois validado.
      Como podemos ver no exemplo, utilizando EasyMock.expect( source.read() ) estamos dizendo ao EasyMock que é esperada uma chamada ao método read do mock, e que esta chamada deve retornar a String “SeuEnium”. Porém, como podemos ver em destination.write("SeuEnium"), não é necessário utilizar EasyMock.expect para mockar uma chamada (neste caso não é nem possível, pois o método write é void, e ocorrerá um erro de compilação caso se tente mockar write utilizando EasyMock.expect). O uso de EasyMock.expect se faz necessário quando queremos especificar um valor de retorno para o método mockado.
      Para indicar ao EasyMock que já configuramos o comportamento do mock e que a partir deste momento o objeto deve se comportar realmente como um objeto “normal”, utilizamos EasyMock.replay( source, destination ). A partir deste ponto, não é mais possível efetuar chamadas a EasyMock.expect, a não ser que se utilize EasyMock.reset( source ).
      Execução do teste da “unidade” – aqui vamos fazer o teste propriamente dito e efetuar quaisquer verificações de resultado da unidade testada.
      Verificação do comportamentoEasyMock.verify( source, destination ) diz ao EasyMock para verificar se os métodos esperados foram chamados – se o comportamento esperado não for satisfeito, o EasyMock irá disparar um exceção, fazendo o teste unitário falhar.

O EasyMock oferece uma grande flexibilidade na especificação do comportamento dos mocks, o que permite que sejam testados muitos cenários que de outro modo seriam difíceis de testar – por exemplo, vamos supor que queremos verificar que nosso Processor se comporte de uma determinada maneira quando ocorrer um problema ao ler do banco de dados. Podemos dizer ao EasyMock para disparar uma exceção no momento de leitura, e verificar o comportamento do Processor quando isso acontece.

   @Test
   public void testProcessWhenReadFails() {
      // Criação dos mocks e configurando o comportamento esperado
      Source source = EasyMock.createMock(Source.class);
      Destination destination = EasyMock.createMock(Destination.class);
 
      // Especificando o disparo de uma exceção
      EasyMock.expect(source.read()).andThrow(new RuntimeException("Erro na leitura"));
 
      EasyMock.replay(source, destination);
 
      // Testando a nossa "unidade"
      Processor processor = new Processor( source, destination );
 
      processor.process();
 
      // Verificando o comportamento
      EasyMock.verify(source, destination);
   }

Neste código estamos testando que Processor nunca irá tentar escrever os dados pela rede quando houver uma exceção na leitura dos dados – Como não configuramos nenhum comportamento para destination, qualquer chamada a métodos desse objeto irá disparar uma exceção.

Digamos agora que gostaríamos de testar o comportamento de Processor quando ocorrer um erro ao escrever pela rede. Neste caso, gostaríamos que uma exceção fosse lançada pelo próprio Processor, para notificar o erro.

   @Test(expected=ProcessorException.class)
   public void testProcessWhenWriteFails() {
      // Criação dos mocks e configurando o comportamento esperado
      Source source = EasyMock.createMock(Source.class);
      Destination destination = EasyMock.createMock(Destination.class);
 
      // Especificando o disparo de uma exceção
      EasyMock.expect(source.read()).andReturn("SeuEnium");
      destination.write("SeuEnium");
      EasyMock.expectLastCall().andThrow( new RuntimeException("Erro na escrita") );
 
      EasyMock.replay(source, destination);
 
      // Testando a nossa "unidade"
      Processor processor = new Processor( source, destination );
 
      processor.process();
   }

Um outro ponto em que o EasyMock oferece flexibilidade é na verificação dos parâmetros passados para as chamadas ao mock. Por padrão, o EasyMock irá utilizar o equals() para verificar se o parâmetro fornecido é o mesmo que foi configurado como esperado. Porém, algumas vezes esse comportamento pode ser restritivo, e o EasyMock oferece formas para mudarmos a maneira como ele irá verificar os parâmetros.

Por exemplo, o no processor sabe interpretar o comando “[[Time]]”. Quando essa String é recebida, o processor envia pela rede o tempo em milissegundos atual. Da maneira como está implementado, o tempo enviado irá ser diferente a cada execução do teste. Há diversas maneiras de testar este tipo de comportamento, e a que vamos utilizar aqui não é a melhor delas, mas ela ilustra o conceito. Vamos utilizar um regexp para validar se foi enviado o tempo para o destino.

   @Test
   public void testProcess2() {
      // Criação dos mocks e configurando o comportamento esperado
      Source source = EasyMock.createMock(Source.class);
      Destination destination = EasyMock.createMock(Destination.class);
 
      // Especificando o disparo de uma exceção
      EasyMock.expect(source.read()).andReturn("[[Time]]");
      destination.write( EasyMock.matches( "time: \\d+" ) );
 
      EasyMock.replay(source, destination);
 
      // Testando a nossa "unidade"
      Processor processor = new Processor( source, destination );
 
      processor.process();
   }

Bom pessoal, essa foi uma introdução ao uso do EasyMock para facilitar testes de unidade. No próximo post, vamos dar uma olhada em um exemplo um pouco menos vago, e vamos ver como efetuar mock de classes realmente, e não somente de interfaces.

Um abraço.

Novos recursos do Selenium Grid

17 de março de 2010 por Enium

Saiu ontem a versão 1.0.5 do Selenium Grid, e com ela veio uma das funcionalidades mais esperadas: o gerenciamento dos Remote Controls conectados ao hub.

Antes, se um Remote Control (RC) estivesse fora por algum motivo inesperado, ele continuava disponível no hub, o que fazia com que se algum cliente tentasse se conectar a esse RC ele receberia um erro.

Agora, se um RC está fora do ar, ele sai automaticamente da lista de RCs disponíveis. Essa retirada pode ocorrer por três diferentes motivos:

  • Se um cliente solicita uma sessão ao Hub e ao tentar reservar um RC, esse RC está indisponível
  • Se o RC não responder a uma chamada periódica do hub para verficar se o RC está vivo. Esse mecanismo se chama hearbeat mechanism, que traduzindo é uma checagem do batimento cardíaco. A frequência dessa checagem é de 3 minutos. Você pode alterar esse valor no grid_configuration.yml usando a propriedade remoteControlPollingIntervalInSeconds
  • Se uma sessão do RC está idle por mais de um tempo configurável. O valor default é a cada 5 minutos e você pode alterar isso no grid_configuration.yml usando a propriedade sessionMaxIdleTimeInSeconds

Outro cenário que poderia ocorrer e que foi corrigido é se você tivesse que reiniciar o hub, você perderia todos os RCs conectados a ele. Foi criada uma configuração para que cada RC pingue o hub a cada X segundos configuráveis. Com isso você pode reiniciar o hub e é só uma questão de segundos até que todos os RCs disponíveis voltem a ficar disponíveis para serem usados. A frequência dessa checagem é a cada 30 segundos, mas você pode alterar isso ao iniciar o RC:

ant -DhubPollerIntervalInSeconds=120 launch-remote-control

É claro que todas essas checagens consomem recursos da máquina e da rede, mas vale muito a pena, já que antes não havia nenhum gerenciamento e era uma dor de cabeça quando você tinha algum problema de RCs indisponíveis ou travados.

Para mais informações leia essa documentação em inglês.

Outra notícia que saiu, é que o mantenedor do projeto opensource do Selenium Grid irá mudar. O desenvolvedor atual está sem tempo e sem prioridades para manter o projeto e está em busca de um sucessor. Para ler mais sobre isso acesse aqui.

Até a próxima.