Utilitários de teste 2

Posted by Adam Brandizzi Thu, 20 May 2010 13:15:00 GMT

E-Plamtax foi um projeto muito positivo que executamos para a Força Aérea. A equipe do E-Plamtax aprendeu muitas coisas no projeto, mas muitas dessas aprendizagens ficaram guardadas conosco. Uma das mais interessantes é a criação de utilitários de teste.

Utilitários de teste são uma maneira de reaproveitar código em testes unitários. Usualmente, isso é feito utilizando os métodos setUp ou @Before dos casos de teste, mas isso tem algumas desvantagens. Por exemplo, em um caso de teste, podemos ter a seguinte inicialização:

    private Address address;
    private AddressDAO addressDAO;

    @Before
    public void setUp() {
        address = new Address();
        address.setStreet("Rua fulano");
        address.setNumber("123/A");
        addressDAO = new AddressDAO();
    }

Se tivermos um teste com o abaixo essa inicialização funciona bem…

    @Test
    public void testGetAllAddresses(){
        addressDAO.addAddress(address);

        List<Address> addresses = addressDAO.getAllAddresses();

        assertEquals(1, addresses.size());
        assertEquals("Rua fulano", addresses.get(0).getStreet());
        assertEquals("123/A", addresses.get(0).getNumber());
    } 

Agora, se tivermos o teste abaixo, o objeto criado é desperdiçado:

    @Test
    public void testGetNoAddress() {
        List<Address> addresses = addressDAO.getAllAddresses();

        assertEquals(0, addresses.size());
    }
 

Se o código for como o seguinte, teremos redundância de código. também temos de decidir SE o outro objeto deve ser criado no @Before também ou no método.

    @Test
    public void testGetAllAddressesMoreThanOne() {
        addressDAO.addAddress(address);
        Address address2 = new Address();
        address2.setStreet("Outra rua");
        address2.setNumber("111");
        addressDAO.addAddress(address2);
        List<Address> addresses = addressDAO.getAllAddresses(); 
        assertEquals(1, addresses.size());
        assertEquals("Rua fulano", addresses.get(0).getStreet());
        assertEquals("123/A", addresses.get(0).getNumber()); 
    }

Esses inconvenientes são menores quando comparados à tarefa de criar as dependências e um objeto para o teste. Por exemplo, para testar uma classe Person que agrega um Address em um outro caso de teste, teremos de ter um @Before semelhante a esse:

    private Person person;
    private Address address;
    private PersonDAO personDAO;

    @Before     
    public void setUp() {
        address = new Address();
        address.setStreet("Rua fulano");
        address.setNumber("123/A");
        person = new Person();
        person.setName("João");
        person.setAddress(address);
        personDAO = new PersonDAO();
    } 

O código para a criação de endereços replicou-se, e é difícil criar as dependências. Nesses exemplos, vemos casos simples, mas é fácil visualizar como a situação irá se complicar.

Nós solucionamos esse problema criando uma classe para criar esses objetos. Essa classe seria algo como isso:

    public class TestUtil {
        public static Address utilCreateAddress(String street, String number) {
            Address address = new Address();
            address.setStreet("Rua fulano");
            address.setNumber("123/A");
            return address;     
        }

        public static Person utilCreatePerson(String name, Address address) {
            Person person = new Person();
            person.setName(name);
            person.setAddress(address);
            return person;
        }
    }

Nossos casos de teste estendiam a TestUtil, facilitando a criação de objetos:

public class TestAddress2 extends TestUtil {
    private AddressDAO addressDAO = new AddressDAO();

    @Test
    public void testGetAllAddresses() {
        Address address = utilCreateAddress("Rua fulano", "123/A");
        addressDAO.addAddress(address);

        List<Address> addresses = addressDAO.getAllAddresses();

        assertEquals(1, addresses.size());
        assertEquals("Rua fulano", addresses.get(0).getStreet());
        assertEquals("123/A", addresses.get(0).getNumber());
    }

    @Test
    public void testGetNoAddress() {
        List<Address> addresses = addressDAO.getAllAddresses();

        assertEquals(0, addresses.size());
    }

    @Test
    public void testGetAllAddressesMoreThanOne() {
        Address address = utilCreateAddress("Rua fulano", "123/A");
        Address address2 = utilCreateAddress("Outra rua", "111");
        addressDAO.addAddress(address);
        addressDAO.addAddress(address2);

        List<Address> addresses = addressDAO.getAllAddresses();

        assertEquals(2, addresses.size());
        assertEquals("Rua fulano", addresses.get(0).getStreet());
        assertEquals("123/A", addresses.get(0).getNumber());
    } 
} 

Como também precisávamos frequentemente de um objeto qualquer, ou que apenas um ou outro parâmetro fosse definido, criávamos variantes dos métodos:

    public static Address utilCreateAddress() {
        return utilCreateAddress("Qualquer", "Qualquer");
    }

    public static Person utilCreatePerson() {
        return utilCreatePerson("José", utilCreateAddress());
    } 

O E-Plamtax foi um projeto um tanto complexo, com grandes redes de dependências de objetos. O uso desses utilitários de teste viabilizou a prática de TDD no sistema. Era emocionante descobrir que, para criar aquele documento que dependia de sete outros documentos e uns cinco ou seis usuários, bastava chamar um método :)

Naturalmente, há mais sobre nossos utilitários de teste do que foi escrito aqui, e pode haver mais ainda que sequer fizemos. (Por exemplo, pode ser interessante produzir utilitários de teste para classes específicas, ao invés de um gigantesco utilitário) Entretanto, como a ideia é bem simples, esperamos que esse pontapé inicial lhe motive a pensar sobre o tema. Até mais!

Desenvolvimento de portlets com Rails 3

Posted by Túlio Ornelas Tue, 19 Jan 2010 13:08:00 GMT

No final do ano passado fechamos um contrato com o Conselho Federal de Administração (CFA) para o desenvolvimento do cadastro integrado de administradores do Brasil dentre outras funcionalidades. Além da implementação, o CFA também tinha a necessidade de uma ferramenta capaz de prover recursos de CMS, comunidades, fóruns, etc. Tendo em vista esse cenário ficou decidido que o Liferay iria ser a ferramenta de portal utilizada enquanto o desenvolvimento dos portlets seria feito em Ruby/Rails.

Como seria possível desenvolver um portlet Ruby em uma plataforma Java? o.O? Utilizando JRuby é claro! Dentre os projetos que viabilizavam uso do Ruby/Rails em portlets java, o rails-portlet foi o que apresentou a melhor proposta. E como ele funciona?

  • 1 portlet java
  • O projeto feito com o Rails empacotado com a gem warble, rodando com o JRuby
  • Comunicação HTTP entre o portlet e o projeto Rails
  • Rails inacessível sem o portlet


O portlet java, que é provido pelo projeto rails-portlet, é adicionado ao portlet container e irá conversar com a aplicação feita em Ruby, isso facilita muito o trabalho, pois conseguimos desenvolver tudo em Ruby e com alguns comandos geramos o .war do portlet.

O projeto feito com o Rails tem algumas particularidades, a mais proeminente é o mapeamento das rotas, pois no projeto original cada método de controller gerava um novo portlet, um mapeamento fixo, por exemplo:

map.portlet_exemplo(

‘portlet_exemplo’, :controller => :controller_1, :action => :method_1

)   

Com as contribuições que nossa equipe fez ao projeto, nós conseguimos criar rotas que abrangem N controllers, o que melhorou bastante o processo de reaproveitamento de código, exemplo:

map.portlet_exemplo(

‘portlet_exemplo/:controller/:action’, :controller => :controller_1

)

Nessa caso, utilizamos um namespace ‘portlet_exemplo’ para definir o portlet e definimos que o controller padrão será o :controller_1 e o método padrão será o :index, que no caso, não precisa ser informado. Os wildcards :controller e :action serão substituídos pelos  valores passados por parâmetro na URL, por exemplo:

http://…/portlet_exemplo
controller_1, método index


http://…/portlet_exemplo/meu_controller

meu_controller, método index


http://…/portlet_exemplo/outro_controller/outro_metodo
outro_controller, método outro_metodo

 

Outra necessidade é a utilização da gem caterpillar que é a responsável por gerar automaticamente os xmls de configuração do portlet e do liferay, além de empacotar utilizando o warbler e realizar o deploy. Essa gem tem como dependência a gem lportal, que contém as tabelas do liferay na forma de modelos do ActiveRecord. Infelizmente o lportal não atendeu as nossas necessidades pois ele apresentou algumas problemas básicos, talvez por inatividade do projeto. Dessa forma nós criamos o projeto liferay_models, que ainda não está público, e que é assunto para um outro post.

Após o panorama geral, vejamos como criar um portlet em Rails.

1) Instalar e configurar o GEM

criar variável de ambiente $GEM_HOME=/caminho/das/gems/sem/a/pasta/gems
* Atenção: O caminho das gems não inclui a pasta gems.
Por exemplo:
export GEM_HOME=/usr/lib/ruby/gems/1.8

1) Instalar e configurar o JRuby

download
http://jruby.kenai.com/downloads/1.4.0/jruby-bin-1.4.0.zip

criar variável $JRUBY_HOME=/… e adicionar no path $JRUBY_HOME:$JRUBY_HOME/bin

1.5)
    apt-get install ruby-dev
    
Ubuntu:
     apt-get install libpqxx3-dev
    Debian:
     apt-get install libpq-dev libpgsql-ruby


2) Instalar gems

gem install jruby-openssl
gem install jruby-jars
gem install hpricot
gem install warbler
gem install caterpillar
gem install lportal
gem install uuidtools
gem install rails -v=2.3.3 (Até o momento o caterpillar só funciona com essa versão do rails, estamos trabalhando nisso)

* no caso de utilizar postgres
gem install pg
gem install activerecord-jdbcpostgresql-adapter

3) Criar projeto

rails nome-projeto
cd nome-projeto

ruby script/generate controller example index

- Configure a rota

map.example(‘example/index’, {:controller => ‘example’, :action => ‘index’})

- Adicionar as dependências das gems no config/environment.rb
config.gem "caterpillar"
config.gem "lportal"

- Configurar config/database.yml
development:
adapter: postgresql
database: lportal
username: postgres
password: postgres
host: 127.0.0.1
timeout: 5000

production:
adapter: jdbcpostgresql
database:
lportal
username: postgres
password: postgres
host: 127.0.0.1
encoding: unicode

- Ativar caterpillar

ruby script/generate caterpillar

- No arquivo config/portlets.rb adicione
portlet.container.root = ‘/../Programas/liferay-portal-5.2.3/tomcat-6.0.18/’
portlet.category = ‘Rails-apps’ (ou um nome que você preferir)

- Deploy

* Teste a conexao com:
caterpillar portlets

- Gerar o arquivo warble.rb
warble config

- Adicionar essa configuração no warble.rb
config.gems << "activerecord-jdbcpostgresql-adapter"
config.gems << "lportal"

# Precisa fazer apenas uma vez
caterpillar jar:install (Coloca o portlet genérico que trata as requisições no liferay)

# Sempre que mudar alguma configuracao e for testar a aplicação no liferay
caterpillar xml
caterpillar warble (nesse momento não pode ter nenhuma gem nativa no environment.rb, exemplo pg)

# Utilizado para atualizar os arquivos no container
caterpillar deploy:xml
caterpillar deploy:war

Após realizar os passos acima, inicie o Liferay e acesse a aplicação. Selecione o portlet rails que se encontra na categoria que foi configurada. Pronto, nós temos nosso portlet rails rodando!

Esse foi o primeiro de uma série de posts sobre o assunto. Fiquem no aguardo.

Equipe CFA:
Túlio Ornelas, Pedro Dias, Bruce Rodrigues e Renan Mendes.

LinguÁgil 2009 1

Posted by Alê! Fri, 23 Oct 2009 19:49:00 GMT

LinguÁgil2009



A proliferação de tecnologias para o desenvolvimento de aplicações web vem gerando exaustivas discussões sobre qual adotá-las em seus projetos. Java, PHP e Ruby estão entre as 10 linguagens de programação mais utilizadas no mundo, segundo a TIOBE Programming Community. Em paralelo, os mesmos profissionais buscam melhorar seus serviços adotando metodologias que ao mesmo tempo permitam o controle de seus projetos, gerem valor agregado aos clientes e evitem excesso de burocracia.

Diante desse cenário, os grupos AgileBahia, JavaBahia, PHPBahia e RailsBahia realizarão em Salvador a edição 2009 do LinguÁgil - Misturando Linguagens e Agilidade, parte da XII Semana de Informática da Unime. Inédito na Bahia, o evento reune algumas das principais comunidades de TI, buscando estimular aprendizado e discussões em torno de linguagens de programação e metodologias ágeis.

Local:

Unime - Lauro de Freitas - Bahia

Palestrantes/instrutores

Alberto “Spock” Lemos (Globalcode), Alexandre Gomes (SEA Tecnologia), Dairton Bassi (Neurobox), Daniel Lopes (Área Criações), Felipe Ribeiro (UFCG), Felipe Rodrigues (Fratech), Henrique Landim (Partner Process) e outros

Palestras GRATUITAS (14/11)

Agile, Manifesto 2.0, Ruby On Rails, PHP/Frameworks, JSF 2.0/Scrum Toys, Linguagens para a JVM, Pentaho

Oficinas/Coding-Dojo (12 e 13/11)

Coding-Dojo Agile, Java/Web com Demoiselle, Integração Contínua/Maven (a confirmar), Python (a confirmar)

Mini-cursos (R$ 60 a R$ 120)

12/11 - Métodos Ágeis, JSF, Portlets com Liferay, TDD/Java, Ruby
13/11 - XP, Scrum, Pentaho, PHP/TDD, Rails

Inscrições:

Com desconto até 05/11
Preços promocionais para estudantes e membros do AgileBahia / JavaBahia / PHPBahia / RailsBahia

Programação detalhada, inscrições e mais informações em www.linguagil.com.br