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

Troubleshooting cglib AOP Exception

 

Olá Pessoal,

O post esse acho que é o menor que já escrevi. Vamos ver como resolver a exceção AopConfigException quando estamos adicionando ao nosso projeto Java. veja:

O problema

Se você está recebendo:

org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.

Solução

Adicione cglib ao seu projeto, faça o download http://cglib.sourceforge.net/

Muito simples não?

Abraços, see ya!! 

Troubleshooting: Maven HSQLDB Exception Hibernate 4

 

Olá pessoal,

O troubleshooting de hoje é bem simples, pelo menos nesse aqui não levei mais que 20 min para achar a solução. Migrando de Hibernate 3.x para  4.x  tive um problema com os testes que rodam com HSQLDB ao executar mvn test. Vamos ver o problema.

Lets go…

O problema

Ao executar os testes localmente fora do maven pelo Eclipse, funcionava normalmente, claro tinham as libs corretas no meu classpath, mas ao rodar pelo maven, os testes que usavam HSQLDB falhavam e com a seguinte exceção:

org.hibernate.exception.GenericJDBCException: This function is not supported

Caused by: java.sql.SQLException: This function is not supported

 

O motivo

A dependência para o HSQLDB deve ser:

<dependency>

<groupId>org.hsqldb</groupId>

<artifactId>hsqldb</artifactId>

<version>2.2.8</version>

</dependency>

 

Porém é comum declararmos:

<dependency>

<groupId>hsqldb</groupId>

<artifactId>hsqldb</artifactId>

<version>1.8.0.10</version>

</dependency>

 

Não use essa última, pois ela não dá suporte ao Hibernate 4. Não cheguei a testar se no Hibernate 3 há o mesmo problema.

Feita a alteração, rode mvn test e veja que seus testes passarão normalmente.

É isso ai, vivendo e aprendendo. Vou ficando por aqui…

Abraços, see ya!! 

Configurando o Jboss 7 no maven

 

Olá Pessoal,

O post de hoje vamos ver como configurar o JBoss AS 7 no maven sem precisar ter o Jboss Application Server instalado na máquina.

Lets go…

 

Starting…

 

1. Crie um maven project 

2. Escolha o tipo de projeto: jboss-javaee6-webappp

 

archetypejboss

3. Informe as configurações do seu projeto na próxima tela. 

4. O arquivo pom.xml vai ficar reclamando de algumas dependências. Apague todas as dependências de Hibernate, porque não vamos usar aqui.

 

5. Vá no pom e altere jboss-as-maven-plugin para versão 7.3.Final, ficando assim:

 

<plugin>

            <groupId>org.jboss.as.plugins</groupId>

            <artifactId>jboss-as-maven-plugin</artifactId>

            <version>7.3.Final</version>

         </plugin>

 

6. Run >> run configuration >> Maven

 jbossasrun

7. E clique em run

 

Aguarde o server subir e fazer o deploy da sua aplicação:

 consolejbossrun

Resultado:

runappjboss7

Pronto! já temos o jboss AS 7 rodando agora é só fazer dpeloy da app, e em segundos já temos aplicação no ar. Simples e fácil não? 

vou ficando por aqui e espero que tenham gostado do post. 

abracos, see ya!!! 

Série Spring: JEE:CRUD Hibernate com Spring 3 + JSF 2.0

 

Olá Pessoal,

Continuando a nossa série de post sobre o Spring vamos, ver hoje como fazer um simples CRUD com Spring + Hibernate + JSF.O objetivo maior, é para quem está chegando possa ver como juntar as tecnologias de maneira simples. E o melhor de tudo veremos como Spring  é uma mão na roda de verdade.

Lets go…

Starting…

A nossa aplicação será super simples, vamos fazer o cadastramento de carros, e exercitar o CRUD. Para exibição e cadastro dos veículos, vamos fazer uma página JSF de maneira mais simples possível e que seja funcional.  A seguir os requisitos:

Requisitos:

  • – MysqlSQL 5.x
  • – Hibernate 3.x
  • – Spring 3.x
  • – Tomcat 7.x
  • – JSF 2.x
  • – Jboss tools

Vou considerar que você vem acompanhando a série de posts  Spring no blog e alguns pontos que já foi tratado aqui, não estarei explicando novamente, dúvidas? Farei um link para o post referente. E sobre JSF 2.x também irei considerar que vc já brincou com o framework, mesmo que seja na versão anterior. Estou ressaltando isso, para que não entre no detalhes de cada ponto, e que o post fique mais direto e mão na massa.

 Configuração

Primeiro ponto é , criar um projeto JSF Project (é preciso ter o jboss tools instalado).

projetocrudspringcar

Escolha a opção JSF 2 na tela do assistente.  Em seguida crie os packages conforme a seguir, por enquanto eles estarão vazios, mas iremos daqui a pouco colocar carne no esqueleto : ).

Adicione os .jars na pasta lib do projeto:

webinflib

Criando o source unit/test

Observe que eu criei um source para os unit tests:

unitestscarcrud

Agora vamos criar o arquivo de configuração do Spring. Na verdade teremos dois, um para os unit tests e outro para aplicação. Apenas dupliquei, mas poderíamos otimizar o de unit tests importando apenas o que precisamos a partir do arquivo principal, mas não quis fazer isso por agora, vamos focar no CRUD.

Crie um arquivo springconfiguration.xml  dentro de WEB-INF, o nome poderia ser qualquer um, normalmente utiliza-se applicaiton-context.xml, mas quis fazer diferente para que você veja que o nome não importa.

Não irei adicionar o cabeçalho apenas o código, que não tem nada de diferente do que já vimos nos posts quando vimos hibernate com Spring.

<context:component-scan base-package=“*”/>

<tx:annotation-driven/> 

<tx:advice id=“txAdvice”>

<tx:attributes>

<tx:method name=“add*” propagation=“REQUIRED”/>

<tx:method name=“delete*” propagation=“REQUIRED”/>

<tx:method name=“read*” propagation=“REQUIRED”/>

<tx:method name=“*” propagation=“SUPPORTS” read-only=“true”/>

</tx:attributes>

</tx:advice> 

<aop:config>

<aop:advisor pointcut = “execution(* *..CarDAO.*(..)))” advice-ref=“txAdvice”/>

</aop:config> 

<bean class=“org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor”/> 

<bean id=“dataSource” class=“org.springframework.jdbc.datasource.DriverManagerDataSource”>

<property name=“driverClassName” value=“com.mysql.jdbc.Driver”/>

<property name=“url” value=“jdbc:mysql://localhost/test”/>

<property name=“username” value=“root”/>

<property name=“password” value=“camilo2593”/>

</bean> 

<bean id=“sessionFactory” class=“org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean”>

<property name=“dataSource” ref=“dataSource”/>

<property name=“packagesToScan” value=“br.com.camilolopes.car.domain.bean”/>

<property name=“hibernateProperties”>

<props>

<prop key=“hibernate.dialect”>org.hibernate.dialect.MySQL5InnoDBDialect</prop>

<prop key=“hibernate.hbm2ddl.auto”>update</prop>

</props>

</property>

</bean>

<bean id=“transactionManager” class=“org.springframework.orm.hibernate3.HibernateTransactionManager”>

<property name=“sessionFactory” ref=“sessionFactory”/>

</bean>

 

Agora precisamos fazer umas configurações no arquivo web.xml

<!– dizendo onde está meu arquivo de configuração –>

 <context-param>

  <param-name>contextConfigLocation</param-name>

  <param-value>/WEB-INF/springconfiguration.xml,</param-value>

 </context-param>

 <!– configurando o context loader do Spring, esse cara permite carregar N arquivos de configuração –>

 <listener>

  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

 </listener>

 <!– esse cara permite dizer ao JSF que os beans serão gerenciados pelo Spring é requerido ter essa

 configuração –>

 <listener>

  <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>

 </listener>

 Testando.

Se você subir aplicação agora, não há nade especial, apenas vai subir o exemplo que temos no JSF Project que é criado pelo Jboss tols. Mas, é bom testar para garantir que as mudanças que fizemos no web.xml , não afetou nada da aplicação.

Arquivo de configuração do spring para unit tests

Agora vamos criar um arquivo de configuração para executar os unit tests. Mas, pq? Simplesmente pq a partir de uma classe de teste você não consegue ler um arquivo que está em web-inf, então você precisa ter o arquivo em source.

Noticia boa: o código é o mesmo que  do arquivo anterior, então duplique o XML apenas, o meu chamei de springconfiguration-test.xml e coloquei no JavaSource:

sourcespringconfiuration-test

Agora vamos começar a brincadeira, ou seja, desenvolver.

Development

Começaremos pelos testes claro. Para isso criaremos uma classe que testará o serviço que implicitamente testa as classes DAO.

Antes criaremos os testes precisamos entender que é importante entender que:

– após testes terem sido executados este deve dar rollback, para que os dados não fiquem no banco;

– os testes não podem ser dependentes de outro test, ou seja, um @Test não pode depender da execução de outro @Test

Por enquanto, ao criar os unit test é esperado que nem compile, já que não temos nenhuma classe pronto, mas é isso que queremos, que os testes nos ensinem a  desenvolver as regras de negocio que precisamos.

O primeiro teste vai nos permitir  testar o salvarOrUpdate  da nossa aplicação, poderia ter separado em dois testes um para save e outro para update, mas não quis entrar muito detalhes sobre testes aqui, senão o post ia fica 2x maior e sinceramente não curto muito posts grandes.

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations={“classpath:springconfiguration-test.xml”})

@TransactionConfiguration(transactionManager=”transactionManager”,defaultRollback=true)

@Transactional

public class CarServiceImplTest {

      @Autowired

      private CarServices carServices;

      private Car car;

      @Before

      public void setUp() throws Exception {

      car = new Car();

      car.setDescription(“ferrari”);

      car.setPriceSale(BigDecimal.ZERO);

      car.setYear(“2010”);

      }

      @Test

      public void testSaveOrUpdate() {

            try{

                  carServices.saveOrUpdate(car);

            }catch (Exception e) {

                  fail(“not expected result”);

            }

      }

 

Observe que configuramos o rollback igual a true para tudo, então sempre será feito rollback e nada é inserido no banco. Mas,se você quer inserir no banco para um método especifico, basta anotarmos  no método assim: @Rollback(false) //isso faz inserir no banco 

Note: nesse exemplo não estou usando um banco em memória, então  é preciso que o Mysql esteja rodando para que os testes possam ser executados, o ideal é era fazer os testes rodarem em um banco em memória assim, não teríamos essa dependência, pois o banco seria iniciado sempre que os testes fossem executados.

Agora vamos criar as classes que o Eclipse está reclamando, vamos começar pela entidade Car:

@Entity(name=”SALE_CARS”)

public class Car implements Serializable{

      private static final long serialVersionUID = 2792374994901518817L;

      @Id

      @GeneratedValue

      private Long id;

      private String description;

      private BigDecimal priceSale;

      private String year;

//getters/setters omitidos

 

Services

Vamos criar os serviços, mas antes precisamos ter uma interface para os nossos serviços CRUD então:

public interface CarServices {

      void saveOrUpdate(Car car);

      void delete(Car car);

      List<Car> listAll();

}

 Agora vamos criar a classe em si:

@Service

public class CarServiceImpl implements CarServices {

      @Autowired

      private CarDAO carDAO;     

      public void saveOrUpdate(Car car) {

            carDAO.addCar(car);

      }

//setters CarDAO omitido. Não é preciso criar get.

DAO Interface

Também criaremos uma interface para o DAO e em seguida a implementação do método save

public interface CarDAO {

      void addCar(Car car);

      List<Car> readAll();

      void deleteCar(Long id);     

}

@Repository

public class CarDAOImpl implements CarDAO {

      @Autowired

      private SessionFactory sessionFactory;

           private Session getCurrentSession(){

            return sessionFactory.getCurrentSession();

      }

      public void addCar(Car car) {

            getCurrentSession().saveOrUpdate(car);

      }

//setters sessionFactory ommitido, não é preciso cria get.

Claro que os demais métodos da interface estarão sem código por enquanto, pois o objetivo agora é testar o create do CRUD.

Testando via Unit Tests

Agora vamos rodar o nosso teste e ver o resultado, se você não adicionou o JUNIT4 ao seu projeto, o Eclipse vai fazer a sugestão.

Note: Ao rodar o unit tests e você ter a exceção:

org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available

faça o download http://cglib.sourceforge.net/ e adicione a lib ao seu projeto na pasta web-inf/lib

O resultado

saveorupdategreen

Agora precisamos desenvolver o RUD.  A seguir os testes que foram criados e depois, o código com a resolução:

 @Test

public void testDelete() {

            try{carServices.saveOrUpdate(car);

                  carServices.delete(car);

            }catch (Exception e) {

String notExpectedResult = “Not expected result “+ e.getMessage();

                  fail(notExpectedResult);

            }

      }

      @Test

      public void testListAll() {

            carServices.saveOrUpdate(car);

            assertFalse(carServices.listAll().isEmpty());

      }

 Classe DAO

public List<Car> readAll() {

            return getCurrentSession().createCriteria(Car.class).list();

      } 

      public void deleteCar(Long id) {

            Criteria criteria = getCurrentSession().createCriteria(Car.class);

            criteria.add(Restrictions.eq(“id”, id));

            Car car = (Car) criteria.uniqueResult();

            getCurrentSession().delete(car);

      }

 Classe de Serviço:

      public void delete(Car car) {

            carDAO.deleteCar(car.getId());

      } 

      public List<Car> listAll() {     

            return carDAO.readAll();

      } 

      public void setCarDAO(CarDAO carDAO) {

            this.carDAO = carDAO;

      }

Rodando todos os testes:

reusultadoAlltestescrud

Há um detalhe que fiz de propósito, observe que não tem um teste para validar o update, deixarei esse como motivação para você brincar mais com unit test  : ).

 

resultdbcrudspringunittests

Observe que nosso banco está vazio, ou seja, nada foi adicionado.

JSF

Agora que já sabemos que o nosso CRUD está funcionando, vamos trazer isso para o nosso front-end com JSF.:

Crie uma classe controller

@Controller

public class CarController {

      @Autowired

      private CarServices carServices;

      private Car car;     

      private List<Car> listCars;     

      public CarController() {

            car = new Car();

      }     

      public void save(){

            carServices.saveOrUpdate(car);

            car = new Car();

      } 

      public void delete(){

            carServices.delete(car);

            car = new Car();

      }     

      public List<Car> getListCars() {

            listCars = carServices.listAll();

            return listCars;

      }

                //setters/getters omitidos

Observe que nosso controller conecta com o nosso service. Só isso que precisamos. Se você já brinca com JSF nada de especial por aqui.

Criando  .xhtml

Na verdade vamos alterar o index.xhtml que foi criado por default pelo jboss tools:

<html><head><meta http-equiv=“Refresh” content=“0; URL=pages/sales-car.jsf”/></head></html>

 

Apenas fizemos um redirecionamento para uma página que vamos criar.

sales-car.xhtml

Crie um xhtml, com suporte facelets e adicione o código a seguir:

<body>

<h:form>

<h:commandLink action=“form-car” value=“::Cadastro”/>

</h:form>

</body>

 

Essa página vai levar para a tela de cadastro:

form-car.xhtml

Vamos por parte:

Primeiro temos o código do form:

<h:form>

<h:panelGrid columns=“2”>

<h:outputLabel value=“Car Description: “/>

<h:inputText value=“#{carController.car.description}”/>

<h:outputLabel value=“Sale Price: “/>

<h:inputText value=“#{carController.car.priceSale}” converter=“javax.faces.BigDecimal”/>

<h:outputLabel value=“year:”/>

<h:inputText value=“#{carController.car.year}”/>

<h:commandButton value=“Save” actionListener=“#{carController.save}”/>

</h:panelGrid>

Agora vamos ter o código de uma tabela que exibi o usuário adicionado e permite editar/deletar :

<h:dataTable id=“cartable” value=“#{carController.listCars}” var=“car” cellpadding=“10”>

<h:column>

<f:facet name=“header”>

<h:outputText value=“Id”/>

</f:facet>

#{car.id}

</h:column>

<h:column>

<f:facet name=“header”>

<h:outputText value=“Description”/>

</f:facet>

#{car.description}

</h:column>

<h:column>

<f:facet name=“header”>

<h:outputText value=“Sale Price”/>

</f:facet>

<h:outputText value=“#{car.priceSale}”>

<f:convertNumber type=“currency” maxFractionDigits=“3”/>

</h:outputText>

</h:column> 

<h:column>

<f:facet name=“header”>

<h:outputText value=“Year”/>

</f:facet>

#{car.year}

</h:column> 

<h:column>

<f:facet name=“header”>

<h:outputText value=“Action”/>

</f:facet>

<h:commandLink value=“Delete” action=“#{carController.delete}”>

<f:setPropertyActionListener target=“#{carController.car}” value=“#{car}”/>

</h:commandLink>

<h:commandLink value=” | Edit “>

<f:setPropertyActionListener target=“#{carController.car}”  value=“#{car}”/>

</h:commandLink>

</h:column> 

</h:dataTable>

</h:form>

 

Pronto. Esse é o nosso front-end para testarmos o CRUD, vamos subir aplicação, clique com o botão direito  no projeto e escolha  Run as >> Run on Server

Note: Caso não tenha um servidor selecionado com o projeto o Eclipse vai solicitar que escolha um, no meu caso escolhi o tomcat e informei o local de instalação. Se der tudo certo você terá a tela a seguir:

screenaddjsfcars

Vamos para tela de cadastro clicando no botão “Cadastro”

 

cadcarscreenspring

addingcar

 

carsresultscreen

Verificando no bd:

 

checkingbdcars

Editando:

 

carrdseditjsf

Resultado Edição:

editresultjsfspring

E no banco:

 

editbdcars

 

Ufa! Post longo heim, e olha que reduzir. Mas, vou ficando por aqui. E espero que tenham gostado.

Abraços, see ya!!!