Top Posts

Série NodeJS: Instalando o framework Express

Continue lendo

Utilizando o Selenium para testes Automatizado

Posted by camilolopes | Posted in Agile/Scrum/TDD, Java | Posted on 15-07-2013

1

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

Série Spring: CRUD Spring 3 + Hibernate + Unit Tests

Posted by camilolopes | Posted in Series, Spring | Posted on 01-05-2013

0

Olá Pessoal,

No post de hoje veremos como fazer um simples CRUD usando o Spring, integrando com Hibernate e testando via unit tests com JUNIT4. No último posts vimos apenas uma integração com o Hibernate e também um CRUD usando HibernateTemplate, esse aqui  veremos que na versão 3 do Spring não precisamos mais do HiberanteTemplate e vamos testar nosso código com unit test.

Lets go…

Starting…

Primeiro passo é que  estarei assumindo que você já tem .jars necessário  para o ambiente. Já que esse não é o primeiro post da série, caso contrário terá que baixar os .jars para: driver Mysql 5, Hibernate 3.6, AOP, AspectJ, Spring 3.x.

Antes de começarmos a desenvolver, vamos primeiro estruturar nosso projeto e packages conforme a imagem a seguir:

springrentcarproject

Nosso CRUD será o cadastro  de veículos  que serão alugados. Claro que há muito mais regras de negócios do que a que veremos no exemplo a seguir, porém o nosso objetivo é explorar o framework Spring e não tratar todas as regras de negócio em um post.

  1. Crie a estrutura conforme a imagem acima
  2. Crie o arquivo de configuração de Spring, o qual chamei de springconfiguration.xml, e coloque dentro do package config.
  3.    Agora vamos colocar a carne no nosso XML

Cabeçalho fica assim:

<beans xmlns=“http://www.springframework.org/schema/beans”

xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xmlns:context=“http://www.springframework.org/schema/context”

xmlns:tx=“http://www.springframework.org/schema/tx”

xmlns:aop=“http://www.springframework.org/schema/aop”

xsi:schemaLocation=“http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.0.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx-3.0.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-3.2.xsd”>

 

Estarei comentando mais na frente ou in line apenas o que  ainda não foi abordado nos posts anteriores.

O cara que busca os beans: 

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

 Colocando translation

<!– esse cara faz as traduções das exception checked para as unchecked do Spring –>

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

Data source

<!– pelo nome diz, data source para conexão com o DB –>

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

 

Configurando a SessionFactory

<!– Aqui estamos definido como será a parte de persistêcia, e dizemos que faremos via annotation –>

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

<!– informando a quem estaremos conectado –>

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

<!– dizendo onde estão as classes dominio, ele saberá devido anotação @Entity  –>

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

<!– configurando coisas especificas do Hibernate –>

<property name=“hibernateProperties”>

<props>

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

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

</props>

</property>

</bean>

 

Definindo Transaction

 <!– definindo quem vai gerenciar as transaction, ou seja, será o Hibernate –>

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

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

</bean>

</beans>

Há duas formas de declararmos as transaction no Spring por XML ou Annotation.  Veremos as duas formas, no nosso caso de usarmos o XML faremos com AOP e você entenderá o  motivo:

Via XML

<!– todo medoto que começa com add é required uma transaction –>

<tx:advice id=“txAdvice”>

<tx:attributes>

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

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

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

</tx:attributes>

</tx:advice>

<!– toda classe que extends a interface terá uma referência para o advisor –>

<aop:config>

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

</aop:config>

 

Em alguns contexto dessa forma é bem mais prático que usar Annotations.

 

Via annotation

Remove todo o código XML acima e apenas adiciona a seguinte linha:

<tx:annotation-driven/>

 

Claro que teremos que anotar nas classes/métodos como @Transaction e informar como esse deve se comportar , seguindo o exemplo do XML acima seria algo  assim:

@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)

public class myClass{  }

 

Normalmente você colocaria isso na camada de serviço.Mas, se você está brincando  e não tem uma camada de serviço, pode colocar direto no DAO.

E o método que faria uma das operações de banco ficaria assim:

@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)

      public void save(Car car) {

            getCurrentSession().save(car);}

 

No nosso exemplo vamos não vamos usar Annotations e exploraremos o benefício de usar a versão do XML conforme acima, se vc deixar a tag para annotation no arquivo de configuração o Spring não vai se importar com isso.

Desenvolvimento

Após toda essa configuração, vamos agora desenvolver nossas classes .java. Começando pela classe de domínio:

@Entity

@Table(name=”CARS”)

public class Car implements Serializable{

private static final long serialVersionUID = -2896368465389020843L;

      @Id

      @GeneratedValue

      private Long id;

      private String manufacter;

      private String description;

      private BigDecimal marketValue;

                //getters/setters omitidos

Basicamente isso .

Interface DAO

public interface RentCarDAO {

      void save(Car car);

      List<Car> findAll();

      List<Car> findAllByDescription(String description);

      void update(Car car);

      void delete();

}

Implementação da Interface:

@Repository

public class RentCarDAOImpl implements RentCarDAO {

      @Autowired

      private SessionFactory sessionFactory;

      public Session getCurrentSession(){

            return sessionFactory.getCurrentSession();

      }

      @Override

      public void save(Car car) {

            getCurrentSession().save(car);

      }

      public void setSessionFactory(SessionFactory sessionFactory) {

            this.sessionFactory = sessionFactory;

      }

      @Override

      public List<Car> findAll() {

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

      }

      @Override

public List<Car> findAllByDescription(String description) {

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

createCriteria.add(Restrictions.ilike(“description”, description));

            return (List<Car>) createCriteria.list();

      }

      @Override

      public void update(Car car) {

            getCurrentSession().update(car);

      }

      @Override

      public void delete() {

Query query = getCurrentSession().createQuery(“delete from Car where id >0”);

            query.executeUpdate();

      }

Interface de Serviço

@Service

public interface RentCar {

      void addNewCar(Car car);

      List<Car> findAll();

      List<Car> findCarByDescription(String description);

      void updateCar(Car car);

      void delete();

}

Classe que implementa o Serviço

@Service

public class RentCarServiceImpl implements RentCar {

      @Autowired

      private RentCarDAO rentCarDAO;

      @Override

      public void addNewCar(Car car) {

            rentCarDAO.save(car);

      }

      public void setRentCarDAO(RentCarDAO rentCarDAO) {

            this.rentCarDAO = rentCarDAO;

      }

      @Override

      public List<Car> findAll() {           

            return rentCarDAO.findAll();

      }

      @Override

      public List<Car>findCarByDescription(String description) {

           return (List<Car>) rentCarDAO.findAllByDescription(description);

      }

      @Override

      public void updateCar(Car car) {

            rentCarDAO.update(car);

      }

      @Override

      public void delete() {

      rentCarDAO.delete();     

      }

}

 

Unit Test

Se não reparou quando criou o projeto, temos um source  apenas  para os unit tests, conforme a imagem a seguir:

springrentcarunittestssource

Agora crie a classe de teste. A seguir mostrarei apenas dois simples testes, você deve criar os demais para validar os cenários, não coloquei todos para não ficar mais longo ainda o post.

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations={“classpath:config/springconfiguration.xml”})

public class RentCarServicesTest {

      @Autowired

      private RentCar rentCarServicesImpl;

      private Car car;

      @Before

      public void setUp() throws Exception {

            car = new Car();

      }

      @Test

      public void testAddingNewCarWithSuccess(){

            try{

                  car.setDescription(“Civic”);

                  car.setManufacter(“Honda”);

                  car.setMarketValue(new BigDecimal(740000));

                  rentCarServicesImpl.addNewCar(car );

            }catch (Exception e) {

                  Assert.fail(“not expected result”);

            }

      }

      @Test

      public void testListAllCarIsNotEmpty(){

            assertFalse(rentCarServicesImpl.findAll().isEmpty());

      }

 Resultado

Lembre-se que seu BD precisa está rodando

springhibernateunittestresult

 

Ufa! Esse post foi longo heim, mas não tinha outra forma de mostrar tudo se não fosse assim, e olha que busquei resumir ao máximo possível. Enfim, vou ficando por aqui.

GitHub

Acesse o repositório no github com todos os projetos da série Spring:  https://github.com/camilolopes/workspacespring

Espero que tenham gostado do post.

Abraços, see ya!!