Utilizando o Selenium para testes Automatizado

Olá Pessoal,

No post de hoje vamos ver como usar o Selenium para criação de testes funcionais. A ideia é um teste simples para mostrar a potência do framework e daí cabe a cada um usar de forma que atenda as necessidades do projeto. Para o post vou usar a versão selenium-server-standalone-2.32.0.jar  disponível http://docs.seleniumhq.org/

 lets go…

Overview sobre o Selenium

Bem, se você usar o Google e pesquisar sobre “Selenium unit test” verá vários links para a definição, então não há motivos para repetir no post. Veja no famoso Wikipedia. Há um post que gosto bastante sobre o Selenium  que está no blog da Caelum.

Em poucas palavras, nos permite realizar teste funcionais simulando ações que um usuário estaria fazendo.

Mas por que usar um framework para isso?

Há vários motivos para fazer isso de maneira automatizada, como por exemplo:

  • – produtividade;
  • – qualidade;
  • – custo;
  • – feedback.

Contratar um time de profissionais para fazer testes que você pode automatizar, além de custar caro, o tempo gasto é muito maior que de forma automatizada e isso é importante. Assim podemos contratar profissionais para realizar em pontos estratégicos onde não temos como testar de forma automatizada. Como toda e qualquer ferramenta sempre há uma limitação e ai que entra o fator o humano.

Colocando mão na massa

Vamos colocar a mão na massa e criar um projeto muito simples. Faremos um teste que terá como objetivo acessar uma determinada página na internet e fazer uma pesquisa. Se tudo ocorrer bem, o teste vai passar. Mas, por exemplo, se a página estiver indisponível ou o endereço informado para o teste for inválido o teste vai falhar.  

  1. Crie um Java project e dê o nome que quiser;
  2. Adicione a biblioteca do Selenium ao  classpath do projeto;
  3. Crie uma classe de teste, ou seja, Junit Class. No meu caso criei com o nome de HelloSeleniumTest.java

helloseleniumproject

Vamos criar o nosso primeiro teste que vai acessar a página do Google e pesquisar por “Camilo Lopes”. Veja o código a seguir.

public class HelloSeleniumTest { 

       @Before

       public void setUp() throws Exception {

       } 

       @Test

       public void testSearchInGooglePage() {

             WebDriver driver  = new FirefoxDriver();            

//           Digo qual url para acessar

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

//           Agora vamos buscar o elemento na página

             WebElement inputTextGoogle = driver.findElement(By.name(“q”));

             inputTextGoogle.sendKeys(“Camilo Lopes”);        

/*           faz um submit na página

 *           poderia buscar o botão search e fazer o submit tb.

 */

             inputTextGoogle.submit();            

             assertTrue(driver.getPageSource().contains(driver.findElement(By.id(“gbqfq”)).getText()));

       } 

}

Entendendo o código

Apesar de que em alguns trechos eu coloquei comentários somente para facilitar o entendimento, vou explicar alguns pontos que considero importantes.

WebDriver: é uma interface do Selenium que todo Web Browser Drivers implementa. O Firefox Browser tem  sua implementação, assim como IE e Chrome, cada um com sua particularidade, e é preciso dar uma olhada na documentação sobre como implementar.

Depois que instanciamos o driver,  dizemos a URL que queremos testar (nesse caso será do Google), mas em um projeto JEE, por exemplo, vamos colocar o caminho onde está nossa aplicação.

Em seguida pesquisamos pelos elementos na página, para isso no Chrome podemos usar o atalho F12, clica na lupa que fica no rodapé e clica sobre o input text e ver qual o nome daquele campo. Podemos usar o id, nome etc. Veja:

seleniuminputgooglesearch

Depois que fizemos isso, criamos uma variável para representar esse campo :

WebElement inputTextGoogle = driver.findElement(By.name(“q”));

 

E em seguida invocamos o método sendKeys(…) e passamos o valor que queremos que seja digitado no input. Para descobrir e conhecer melhor os métodos disponíveis tem que passar por alguns minutos vendo o que temos na documentação do framework.

inputTextGoogle.sendKeys(“Camilo Lopes”);

 

Logo em seguida fizemos o submit página

inputTextGoogle.submit();

 

Criando o assert

Bem, para que  seja testado precisamos usar algum assertXXX do framework Junit. Então vamos verificar se após ter feito o submit há um elemento com o id informado na página.

seleniumtestgreen

O teste passa. Na verdade esse teste  não tem nada de inteligente. Se você reparar, ele verifica se o input que pesquisamos na primeira página do Google é o mesmo na página do resultado da busca.

Claro que em nossa aplicação íamos testar algo mais voltado para regras de negócio. E o método getPageSource() nos ajuda nisso, em busca de um elemento na página corrente.

 

Execute o teste

Vamos executar os testes e aguardar por alguns segundos e veremos que o Selenium vai abrir o browser que definimos (no caso do post foi o Firefox)  e realizar a pesquisa.

 seleniumfirefox

Convertendo isso para uma aplicação

Em uma aplicação web, vamos ter que usar a url onde nossa aplicação está rodando. Claro que vamos evitar que o endereço seja informado dentro da classe Java, este pode ser informado de um arquivo .properties por exemplo, efaremos assert voltado para as regras de negócio.

Conclusão

O objetivo desse post não era explorar como escrever bons testes com o Selenium, a ideia era apresentar o framework e vê-lo em ação. Após isso podemos tirar nossas próprias conclusões sobre a eficiência e produtividade gerada  quando usamos corretamente.  Já passei por algumas empresas e projetos onde falaram que o Selenium foi o responsável pelo aumento do dos prazos nas entregas. Acredito que o problema certamente não foi com o Selenium, mas sim na forma de como este foi usado ou adotado dentro do projeto.

 

E você tem usado o Selenium em seus projetos? Compartilhe sua experiência…

Abraços, see ya!!! 

TDD:O seu primeiro TDD em Java

olá Pessoal,

Mais um post da śerie Agiile.Hoje veremos como escrever o seu primeiro TDD em Java (não é “o meu…”, pq este já fiz rs ), na semana passada eu dei um overview dos principios de TDD, nessa vamos praticar da maneira mais simples de ser. No próximo post, mostrarei como faço TDD hoje, após de algumas  “aulas” com o Kent Beck e o dia-dia fui aprimorando.Mas, não poderia de fazer um post para quem está no 0x0 do primeiro tempo :). (não sei pq,mas eu adorei a imagem que temos no inicio do post, passo horas olhando pra ela hehe)

lets go…

O foco

O foco aqui é poder compartilhar com vocês  de modo prático como foi que aprendi TDD. Pois, ainda há muitos programadores que não conseguem entender o uso, ou usar no dia-dia(claro que há exceções onde TDD não se aplica ,porém quando aplicamos este  já comprovou que os resultados são indiscutíveis).

O Exemplo

Antes de tudo vou buscar ser  bem direto ao foco do post e todo o conceito TDD será deixando de lado blz? Qualquer dúvida da uma passada no primeiro post ou no velho Google.

O nosso exemplo é o algo muito comum e escolhi ele, porque eu lembro como se fosse hoje, que  foi a partir dele que o mundo Agile marcou minha vida profissional, pois foi onde conseguir a dar meus primeiros passos ao desenvovimento guiado por testes.Sendo assim,resolvi usá-lo aqui no post. (não é nada chique, desde da faculdade, o que mais vemos é algo como RG, CPF, Locadora ,Estoque etc). Porém, o objetivo aqui não é saber se você sabe validar um RG,CPF,CNPJ, Locadora  etc. E sim se consegue desenvolver usando TDD.

Não esquecer

TDD não é apenas criar unit tests e sim ter testes inteligentes, ou seja, automatizados o suficiente para gritar quando alguém quebrar alguma regra. Outro detalhe não é pq são unit tests que você escreve de qualquer forma, é code então os principios são os mesmos utilizados no código funcional(não sei porque tem gente que separa isso, até hoje não entendi o motivo), na verdade quem desenvolve utilizando TDD tem um carinho enorme com seus testes, pois sabemos da importância deles durante o desenvolvimento e na manutenção. Já vi perguntas do tipo:

– pq não coloca tudo em um teste só? (será que precisa responder o motivo?)

– o que é um bom teste? (essa foi uma boa pergunta)

Primeiro que não há receita de bolo, mas um bom teste ele sempre tem um perfil parecido, grita de forma eficiente, ou seja, não grita por qualquer coisa que mudou, só grita quando algo que ele testa de fato mudou. Qual a diferença? Muita, há testes criados que tem varias responsabilidades e isso já passa ser um problema maior. Daí algo mudou e ele falha, mas a falha daria um novo teste especifico, mas o desenvolvedor que só escreve teste por escrever ou pq é mandatório no projeto, e importante que o teste esteja lá como métrica.

Enfim, Um bom teste deve ser especifico e rápido, assim vc pode executá-lo várias vezes.Isso é algo primário que precisamos ter em mente ao construir nossos testes.

Praticando

No exemplo a seguir temos uma aplicação que faz a “validação” de um nro de uma carteira de identidade. Este é um start-up para você ficar brincando após brincando após a leitura, mas terá que ser persistente e ir mais adiante para olhar o que tem  após omuro. Se não fizer foi ai onde quase todos desistiram.

Primeiro passo

Escrevemos a classe de teste e já fizemos o teste para os possíveis RG inválido/válido.

public class RGTest extends TestCase {

private RG validarg = new RG();

publicvoid testIsValidaRG(){

assertFalse(“retorna FALSE – inválido RG”, validarg.isValidaRG(“128641011”));

assertFalse(“retorna FALSE – RG inválido”, validarg.isValidaRG(null));

assertFalse(“retorna FALSE – RG inválido”, validarg.isValidaRG(“”));

assertTrue(“retorna TRUE – RG válido”, validarg.isValidaRG(“128640-28”));

}

Se for executado vai falhar porque não temos a classe principal “RG” que precisamos implementar. A falha anterior é de compilação, caso você execute.

public class RG {

publicboolean isValidaRG(String rg){

return false;

}

Segundo Passo

Agora precisamos testar e ver se vai falhar, pela teoria deve falhar.

O motivo da falha é que o método isValidaRG(String rg) sempre retorna false, então, nosso teste não está funcionando 100%. Pois, precisamos ter um nro de RG válido.

Terceiro passo

Fazer o teste funcionar, precisamos resolver o problema de ter um RG válido, para isso precisamos alterar o método da classe principal.

public boolean isValidaRG(String rg){

if((rg== null) || (rg.length()!=11)|| (rg.isEmpty()) || rg.charAt(8)!= ‘-‘){

return false;

}

return true;}

Agora estamos validando, os nossos assertXXX da classe teste.

O Bug

O código abaixo passa no teste, observe que não há nenhuma regra validando letras, e sabemos não existe RG com letras. Precisamos criar um teste para isso. E resolver o bug

assertTrue(validarg.isValidaRG(“abcdefgh-ij”));

Quarto passo

criamos um método na classe RGTeste para testar se de fato nossa aplicação NÃO aceita letras, mas pelo resultado abaixo, vimos que aceita, uma vez que o método retorna TRUE, já que não há nada que proíba as letras na classe principal.

//criando um novo método para testar letras

publicvoid testIsValidaRGLetras(){

assertFalse(“retorna FALSE – inválido letras RG”, validarg.isValidaRG(“ABCDEFGH-IJ”));

assertFalse(“retorna FALSE – Inválido letras RG”, validarg.isValidaRG(“G3X8Xopa-22”));}

 Quinto passo

Precisamos agora alterar isso no código principal, para testar que letras não podem passar pelo metodo.

public boolean isValidaRG(String rg){

if((rg== null) || (rg.length()!=11)|| (rg.isEmpty()) || rg.charAt(8)!= ‘-‘){

return false;

}//fim do if

for (int i = 0; i < rg.length(); i++) {

if(i!=8){

char posicao = rg.charAt(i);

//senao for umdigitoretorne false

if(!Character.isDigit(posicao)){

return false;

}}

}return true;

}

Ambos testes passaram, assim sabemos que a validação de RG está correta, até agora. Porém, o que devemos observar que nessa mecânica, fomos escrevendo o nosso código com base nos resultados dos unit tests primeiro e não fazer o inverso. É obvio que falta muito trabalho ainda até termos um RG realmente válido e inválido, mas lembre-se que o básico de TDD é querer fazer a barra verde chegar o quanto antes com o menor esforço possível, é um tal de baby-step. É comum, queremos implementar logo a parte complexa do código, querendo fazer as validações possíveis etc. Mas, é ai que o terreno está propicio para nascer os bugs mais terríveis de nossa vida e só saberemos quando o cliente abrir. Encontrar bugs em modelo como waterfall não é uma tarefa fácil, não é a toa que o custo de manutenção nesse modelo é alto. Lembre-se que devemos desenvolver algo que qualquer outro desenvolvedor possa entender no menor tempo possível, e TDD possibilita isso, eu particularmente, quando pego um código feito com TDD olho primeiros os testes. Os testes sãos os guias que precisamos. :).

 Meu case

No exemplo do post vimos como usar TDD, quando iniciei meus estudos nunca parece vantagem (acho que você deve está com esse sentimento também), olhando apenas a execução e o resultado. Mas, confesso que só conseguir ver a essência de TDD em partes diferente do projeto, uma quando precisamos alterar algo, e manter os testes passando, ou quando recebia novos requisitos e tinha que implementar e criar mais testes, ai vi agilidade em pratica e ficando viciado, sem falar que todo time fica feliz, pelo tempo gasto na manutenção, TDD de fato dar contribuição dele na manutenção de software. Fora que com o tempo vamos vendo o quanto TDD ajuda na construção do nosso design. Daí passamos a ter um tal de design incremental.

Espero que tenham gostado do post, vou ficando por aqui, até o próximo post.

Abracos, see ya!!

New Job – Again 2011 – HP


chimarrao

ae pessoal,

Mais um post em tão curto tempo, sobre new Job. Quem tem acompanhado o blog, sabe que atualmente trabalho em SP na 4Linux em projetos Java da empresa com Linux. Porém, surgiu uma oportunidade para POA, na HP e estou mudando novamente de estado e é bem capaz de o blog ficar atrasado ou com posts desatualizado durante esse time de mudança e adaptação(espero que não fique). Bom, estarei indo trabalhar no Laboratorio de pesquisa e desenvolvimento com Java da HP (ECL). Bom, estou muito feliz(já estava feliz na 4Linux), e é difícil expressar aqui a felicidade de ir fazer parte do time HP. E sempre tive vontade de trabalhar com pesquisa, alem de desenvolvimento.

hp_logo

Sentirei falta dos colegas da 4Linux, que apesar do pouco tempo que fiquei fiz grandes amizades, conheci profissionais de alto nível e sem falar que o “pinguim” tem voz  por aqui, é o capitão da empresa. O presidente da empresa Rodolfo Gobbi é um dos executivos mais humano, humilde, administrador, empreendendor que já conheci. Realmente é um verdadeiro líder. Aproveito o espaço para agradecer pela oportunidade, sinceridade e transparência. Se você é um cara que ama linux, deve passar na 4Linux e conhecer as missoes criticas da empresa com a tecnologia. Eu fiquei pouco tempo e vi no dia-dia o bom trabalho do pinguim e que de fato Linux é Linux.  Acabei tendo um pouco de “sorte” e somente vou para terra do “tchê” em Janeiro, pois nem entrei direito e peguei férias coletivas da HP, devido as festas do final do ano.

Em especial quero agradecer  a uma grande amiga, que conheci cerca de 3 anos atras, pre-ibm, lá no GUJ, e depois na IBM, ficamos amigos e foi a pessoa que fez a indicação da vaga e que vinha falando “aqui na HP ta rolando vagas pra Java nao quer vim nao?”, estou falando da Veronica Nunes. Obrigado moça.

Meu processo:

1. A Veronica fez indicação e 1 ou 2 dias a equipe do RH entrou em contato

2. damos start no processo de entrevistas e apresentação da vaga (realmente HP, so aceita com o cv cadastrado no site deles, funciona o sistema de recebimento via site da HP)

3. uma entrevista técnica do tipo overview

4. uma entrevista em inglês (30min) conversação

5. uma entrevista com um dos gestores do laboratório

6.uma entrevista com um líder técnico – 100% tecnica(java,tdd, restful, refactoring,frameworks java,maven,soa etc)

END. Approved? yes/no

Eu estarei no ECL.

Abaixo algumas informações sobre o job, essas informações não são confidenciais, está no site da HP.

Sobre o Job

BUSINESS ENVIRONMENT
Brazil R&D is an international research and development organization with its R&D Center in Porto Alegre, RS, Brazil. As a HP’s R&D organization, Brazil R&D purpose is to deliver innovative products that provide a competitive advantage for HP, working in collaboration with business units leveraging knowledge horizontally between them. Brazil R&D has 3 laboratories in its R&D Center:
Enterprise Computing Lab (ECL), Enterprise Printing Lab (EPL) and Personal Computing Lab (PCL). This position is for the Enterprise Computing Lab.

There are several products ECL contributes with tools and solutions, participating since the conception of the features till the testing and validation of complex solutions and its support.

Job Description: Responsible for design, development, maintenance, testing, and quality and performance assurance of system software products. Work within this job classification falls into three major categories:

1. Maintenance and enhancement: Makes changes to system software to correct errors in the original implementation and creates extensions to existing programs to add new features or performance improvements;
2. Major enhancement and new product design: Designs and develops major functional or performance enhancements for existing products, or produces new software products or tools;
3. Quality and performance assurance: Reviews requirements, specifications and designs to assure product quality. Develops and implements plans and tests for product quality or performance assurance.

Experience and Skills:

* Experience with Java;
* Must be able to work with other people under a teamwork environment;
* Experience in full software development life cycle and methodologies;
* Experience working with internal and external partners;
* Very experienced communication skills and English fluency.

Concluindo

Bem, vou ficando por aqui, e como sempre eu não deixo de compartilhar minhas experiencias com meus leitores hehe :). Ahh quase esqueço, fiquei sabendo que vou trabalhar do lado de um dos caras feras, que todo javeiro e a galera de ruby conhece, Urubatan.

JNDI com Hibernate – Ambiente de Test

Olá Pessoal,

No post de hoje, vou apresentar como usar JNDI dentro do seu arquivo hibernate.cfg.xml dentro de um ambiente de teste. Em outro post falarei como usar em um ambiente de produção e ver que fica mais fácil realizar mudanças nas conexões de modo mais fácil, uma vez que normalmente o ambiente de teste possui configurações levemente diferente do ambiente de produção desde nome do usuário, até o path do BD.

Lets go…

Starting/Nosso Cenário

Eu já falei aqui no blog sobre pool de conexão no TomCat e JNDI, porém não falei como usar o JNDI dentro do Hibernate.

Aqui veremos isso com um framework bem utilizado no mercado que é o Hibernate.

Mas, a pergunta que você pode está fazendo: “Camilo, por que eu usaria isso?”, “Qual a diferença na pratica?”

Como sempre gostei de ser mais pratico e menos teorico, eu também tive essa dúvida rs. Porém, descobrir a grande produvidade quando tive 6 projetos diferentes para Produção e sempre quando tinhamos um release, era fato de esquecer de mudar o hibernate.cfg.xml, para as conexões de produção, fora que toda vez já era um saco, porque tinha que configurar sempre no ambiente de desenvolvimento antes de enviar para prod.

Enfim, na pratica você só vai configurar em um lugar as config de conexão, em um único arquivo e mais nada. E o melhor, quando for pra PRODUÇÃO, veremos que lá temos outro arquivo JNDI só para PROD, que normalmente não tem porque mudar com frequência. E nos desenvolvedores precisamos apenas saber o JNDI correto, e o administrador do Servidor que se vire lá com as configs, do arquivo de conexão em produção. Isso é extremamente importante, trabalhei em um projeto do qual nos desenvolvedores não tinhamos acesso as senhas, pw de produção, somente os administradores, para nos o que importava era apenas o path do JNDI e mais nada. Para quem trabalha fazendo todos os papeis (isso lembra meu tempo de freelance rs) desenvolvedor,administrador, DBA, isso parece ser estranho, mas em projetos grandes que participei na IBM , não é assim que funciona. Desenvolvedor é desenvolvedor,Testador é testador e por ai vai. E em ambiente teste você tem até acesso ao BD, PW etc. Mas, em produção. Not.

Hoje estarei limitado ao ambiente de teste, porque no ambiente de produção há algumas mudanças significativas e quero deixar o post focado à um assunto.

Nosso projeto

Criei um projeto muito simples, pois a funcionalidade está no uso de JNDI com Hibernate em teste. Não passa de um projeto com JSF + Hibernate. Porém,vc pode configurar isso em qualquer projeto com Hibernate para que ele funcione com JNDI.


Primeiro passo:

É configurar o arquivo web.xml do seu projeto com o nome do JNDI que deseja, pode ser o nome do seu cachorro, da sua namorada, o que você quiser.

<resource-ref>

<res-ref-name>jdbc/lpjava</res-ref-name>

<res-type>javax.sql.DataSource</res-type>

<res-auth>Container</res-auth>

</resource-ref>

Segundo passo:

Após ter configurado o web.xml, informando que a conexão para o BD estará naquele path. Vamos configurar o nosso JNDI, com os dados de conexão. Em ambiente de teste, vamos configurar o arquivo context.xml que está na pasta Server do Eclipse. É nele que vai estar as config locais. Insira dentro da tag Context o Resource abaixo:

<Resource auth=“Container”

name=“jdbc/lpjava”

driverClassName=“com.mysql.jdbc.Driver”

maxActive=“20” maxIdle=“10” maxWait=“-1”

type=“javax.sql.DataSource”

url=“jdbc:mysql://localhost/apptestes”

password=“lpjava”

username=“camilolopes”

validationQuery=“SELECT 1”

testOnBorrow=“true”

testWhileIdle=“true”

timeBetweenEvictionRunsMillis=“10000”

minEvictableIdleTimeMillis=“60000” />

Observe que informamos o nome do JNDI, que este tem referencia.

Terceiro passo:

Feito isso, vamos informar ao Hibernate que ele vai usar uma conexão JNDI, para o Hibernate o que importa é o path, se amanha você muda a senha de conexão vai precisar alterar apenas o arquivo context.xml que está na pasta Server dentro do Eclipse, lembrando que isso em ambiente de teste. Abaixo como ficou meu arquivo hibernate.cfg.xml

<hibernate-configuration>

<session-factory name=“hibernate/SessionFactory”>

<property name=“hibernate.connection.datasource”>java:/comp/env/jdbc/lpjava</property>

<property name=“hibernate.current_session_context_class”>thread</property>

<property name=“hibernate.transaction.factory_class”>org.hibernate.transaction.JDBCTransactionFactory</property>

<property name=“hibernate.dialect”>org.hibernate.dialect.MySQL5InnoDBDialect</property>

<property name=“hibernate.jdbc.batch_size”>0</property>

<mapping class=“br.com.camilolopes.bean.TUsuario”/>

</session-factory>

</hibernate-configuration>

Quem usa o Hibernate ou está começando vai ver que não temos mais a property para o password ou user, uma vez que há uma referencia para um path, onde este tem referencia para um arquivo (context.xml) onde está de fato nossa conexão.

Finalizando

Teste sua aplicação, mande executar e faça uma persistencia, porem não deixe de verificar se já deu um start no banco de dados, se todos os .jars referente ao Hibernate estão no projeto e no caso do Eclipse olhe se está fisicamente na pasta lib do projeto.

Vou ficando por aqui, espero que tenham gostado do post.

Abracos, see ya guys!!! 🙂