Posts com a tag ‘maven’

Screenshot com Selenium – Parte 2, TestNG

23 de abril de 2010

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.

Teste em paralelo com a nova versão do Junit 4.6

14 de abril de 2009

No post anterior mostrei que é possível paralelizar os testes com TestNG.

Para os que estão mais familiarizados com Junit, o TestNG pode parecer mais difícil, mas não se preocupe.

Hoje foi liberada a versão 4.6 do Junit e com ela você consegue paralelizar os seus testes.

Segue o exemplo no release notes de como rodar em paralelo:

public static class Example {
	@Test public void one() throws InterruptedException {
		Thread.sleep(1000);
	}
	@Test public void two() throws InterruptedException {
		Thread.sleep(1000);
	}
}
 
@Test public void testsRunInParallel() {
	long start= System.currentTimeMillis();
	Result result= JUnitCore.runClasses(ParallelComputer.methods(),
			Example.class);
	assertTrue(result.wasSuccessful());
	long end= System.currentTimeMillis();
	assertThat(end - start, betweenInclusive(1000, 1500));
}

Assim como o TestNG você pode escolher entre paralelizar os métodos ou a classe toda: ParallelComputer.methods() ou ParallelComputer.classes()

Para quem usa maven, a integração nativa da versão 4.6 do Junit com o Surefire Plugin funciona somente para testes sequenciais. Se você quiser paralelizar vai ter que seguir o exemplo acima do release notes.
Mas acredito que logo mais sairá uma versão do maven-surefire-plugin em que você apenas terá que colocar na configuração se você quer paralelizar, assim como ocorre com o TestNG, com o config no pom.xml:

<parallel>tests|methods</parallel>

Qualquer outra novidade volto a postar… :)

Inserido em 02/12/2009
*A versão do junit 4.6 estava bugada. Use uma mais recente, 4.7 ou 4.8.

Testes em paralelo com Selenium Grid, Maven e TestNG

5 de abril de 2009

O Selenium se provou ser uma ótima ferramenta para auxiliar os testes em sistemas web. O desenvolvedor ganha mais confiança ao realizar alterações no sistema, os webmasters também e se preocupam cada vez mais em deixar as telas mais fáceis para automatizar e dar manutenção.
Mas à medida que o número de testes aumenta, o tempo total de execução também aumenta, e muito. A maneira de conseguir diminuir esse tempo é usando o Selenium Grid.

O Selenium Grid atua como um proxy entre as requisições dos clientes e um pool de servidores Remote Control. Com isso, o grid consegue gerenciar ao mesmo tempo todos os RCs que estão conectados. O benefício disso tudo é que você pode paralelizar a execução dos seus testes e consequentemente o tempo de execução dos seus testes diminui.

E como você consegue fazer isso?

Primeiro você tem que baixar o Selenium Grid em http://selenium-grid.seleniumhq.org/download.html. A última versão é a 1.0.3.
Descompacte o arquivo baixado em algum lugar de sua preferência.

Você também vai ter que ter o ant instalado em sua máquina. Baixe-o aqui.

Entre no diretório do Selenium Grid e rode o comando para subir o servidor principal, o hub.

ant launch-hub

O hub vai subir na porta 4444 e é onde o seu teste tem que se conectar.

Agora suba dois servidores do Selenium RC com o browser Firefox:

ant -Dport=5556 -Denvironment=*chrome launch-remote-control
ant -Dport=5557 -Denvironment=*chrome launch-remote-control

Acesse agora http://localhost:4444/console e você verá uma tela contendo os servidores disponíveis.

Pronto, você já tem a estrutura de servidores para que seus testes rodem paralelamente.

Agora vamos criar um projeto Maven para que tudo fique organizado e seja fácil disparar os testes (ao fim do post tem um link para fazer download do projeto com o exemplo). Para baixar o Maven acesse aqui.

Rode o seguinte comando para criar um novo projeto de nome “testes-em-paralelo”:

mvn archetype:create -DgroupId=br.com.seuenium -DartifactId=testes-em-paralelo

Esse comando cria uma estrutura básica de diretórios para um projeto Java. Um desses diretórios criados é o src/test/java onde o Maven por convenção vai chamar todos os seus testes que estiverem localizados nessa pasta. Essa convenção é definida pelo plugin maven-surefire-plugin.
Esse plugin consegue rodar tanto testes em Junit como em TestNG.
Para quem não conhece, o TestNG é um framework de testes praticamente igual ao Junit, porém com algumas funcionalidades a mais. Uma dessas funcionalidades é a possibilidade de rodar os seus testes em paralelo.

Para habilitar o TestNG, apenas inclua a dependência da lib do TestNG no seu pom.xml. Vai ficar assim:

<dependency>
	<groupId>org.testng</groupId>
	<artifactId>testng</artifactId>
	<version>5.8</version>
	<scope>test</scope>
	<classifier>jdk15</classifier>
</dependency>

Você também tem que adicionar a dependência da api cliente do Selenium:

<dependency>
	<groupId>org.seleniumhq.selenium.client-drivers</groupId>
	<artifactId>selenium-java-client-driver</artifactId>
	<version>1.0-beta-2</version>
</dependency>

Outra configuração que você precisa fazer, é dizer ao TestNG que seus testes devem rodar em paralelo. Para isso você tem que configurar o maven-surefire-plugin.
Vai ficar assim:

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-surefire-plugin</artifactId>
	<configuration>
		<parallel>tests</parallel>
		<threadCount>2</threadCount>
	</configuration>
</plugin>

Você tem dois possíveis valores para a configuração “parallel”: tests ou methods.

A threadCount equivale a quantos testes vão rodar ao mesmo tempo. No nosso caso vamos usar 2 pois só subimos duas instâncias de servidores Remote Control.

Após você já ter essa estrutura do Maven criada, vamos criar os testes em Java.

Para facilitar o exemplo, criei uma tela para podermos testar tudo isso. Essa tela é uma página de busca, com um input text para você digitar um termo e o botão buscar. Ao clicar no botão o resultado da busca aparece em uma tabela. Se não há resultado aparece uma mensagem informando que não encontrou.

Vamos criar então dois testes para essa tela:

  • Busca com resultado
  • Busca sem resultado

Abra então a Ide do Selenium no Firefox e grave o primeiro teste. Para isso digite o termo “Selenium” e mande buscar. Faça também um verificação de sucesso. Em seguida exporte-o para Java e salve no diretório testes-em-paralelo/src/test/java/br/com/seuenium/ com o nome TesteBuscaComResultado.java.

Faça o mesmo para o segundo teste, porém usando o termo “Seuenium” e salvando o arquivo como TesteBuscaSemResultado.java.

Temos agora duas classes Java que são dois TestCases. Quando se exporta para Java, a IDE cria uma classe de teste que extende um TestCase padrão do Selenium, a SeleneseTestCase. No nosso caso, vamos alterar isso. Vamos criar o nosso TestCase padrão, uma classe abstrata, onde as outras classes de teste irão extender esse cara.
O TestCase abstrato fica mais ou menos assim:

package br.com.seuenium;
 
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import com.thoughtworks.selenium.DefaultSelenium;
 
public abstract class AbstractTestCase {
 
	protected DefaultSelenium selenium;
 
	@BeforeTest(alwaysRun=true)
	public void startSelenium() {
		selenium = new DefaultSelenium("localhost", 4444, 
				"*chrome", "http://seuenium.com.br");
		selenium.start();
	}
 
	@AfterTest(alwaysRun=true)
	public void stopSelenium() {
		selenium.stop();
	}
}

Temos o método startSelenium() que inicializa uma sessão com o Selenium, que no nosso caso é o hub do grid. Temos também o comando stopSelenium() que fecha a sessão com o servidor do Selenium.
Colocando as anotações do TestNG @BeforeTest e @AfterTest, sempre que um teste for executado, ele primeiro vai executar o startSelenium(), em seguida vai rodar o teste e ao fim vai chamar o stopSelenium(). O parâmetro alwaysRun=true garante que mesmo que uma exceção ocorra, esses métodos serão executados.

Agora vamos para os nossos TestCases exportados pela IDE. Primeiro alteramos ele para extender a classe abstrata que acabamos de criar. Em seguida, vamos colocar a anotação @Test na própria classe, dando um valor para o parâmetro chamado “testName”. Você também precisa colocar a anotação @Test no método que contém as chamadas na api do Selenium.
O classe TesteBuscaComResultado então vai ficar assim:

package br.com.seuenium;
 
import static org.testng.Assert.*;
 
import org.testng.annotations.Test;
 
@Test(testName="Teste com resultado")
public class TesteBuscaComResultado extends AbstractTestCase {
 
	@Test
	public void testNew() throws Exception {
		selenium.open("/testes/4/buscar.php");
		selenium.type("q", "Selenium");
		selenium.click("//input[@value='Buscar']");
		selenium.waitForPageToLoad("30000");
		assertTrue(selenium.isTextPresent("2 resultados encontrados com a palavra Selenium"));
	}
}

Faça o mesmo com a outra classe TesteBuscaSemResultado .

Mas por que eu tenho que colocar a anotação @Test na classe e ainda por cima configurar o parâmetro testName?
Bom, isso eu demorei pra entender. Eu estava mais familiarizado com o Junit, onde um teste corresponde a um método anotado com @Test. Para o TestNG um teste corresponde a uma ou mais classes e o que define esse teste é o seu nome. Você até pode ter mais de um teste por classe, mas eles nunca rodarão em paralelo entre si, ou seja, todos os métodos com @Test da mesma classe rodarão sequencialmente.

Agora vamos rodar os testes em paralelo.
Na linha de comando, dentro do projeto testes-em-parelelo, digite:

mvn clean install

Com esse comando, o maven vai compilar as suas classes e vai chamar todos os seus testes.
O resultado esperado disso tem que ser um “BUILD SUCCESSFUL”.
Mas fique atento a parte com os prints dos seus testes. Você vai ver algo parecido com:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running TestSuite
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 10.557 sec
 
Results :
 
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0

Note que 2 testes foram executados e demoraram 10.557 segundos.

Só para ter garantia de que você teve um ganho no tempo de execução dos seus testes, altere no pom.xml o threadCount para 1, para que seu teste rode sequencialmente. Você vai ter um resultado parecido como esse:

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 19.402 sec

Praticamente o dobro do tempo demorou.

Bom, vimos que é possível paralelizar os testes e ganhar tempo na execução. Há também um outro carinha que paraleliza testes em Java, é o Parallel Junit, mas eu não encontrei uma integração desse cara com o maven.
Mas e se meus testes não estão escritos em Java? Há frameworks que fazem isso para outras linguagens. Em Ruby por exemplo você tem o DeepTest. Para mais informações dê uma olhada no faq do Selenium Grid, clique aqui.

O projeto Maven completo com todas as classes e tudo configurado, pronto pra rodar, você pode baixar AQUI.

Bom, é isso. Qualquer dúvida só perguntar. :)