sábado, 12 de dezembro de 2009

Unit tests para testar modelos

Agora aprofundarei mais no assunto Unit Tests. Na verdade, o uso desse termo no Rails é incorreto, porque "testes de unidade" fazem testes de mecanismos e/ou objetos de forma independente do restante do sistema.

Em outras palavras, quando você faz um teste de unidade, testa apenas aquela unidade do sistema. Caso você necessite de interação com outros objetos nesse tipo de teste, você recorre a objetos mock, que seriam simulações ou simplificações dos objetos reais.

Esse isolamento é necessário para manter as interfaces do objeto simples e o código limpo, com um design simplificado.

No Rails, por outro lado, esse isolamento não ocorre. Por quê? Não tenho certeza. Mas, na prática, o funcionamento dos testes de unidade no Rails não diferem tanto quanto um teste de unidade comum, já que você provavelmente não vai chamar nenhuma função de um modelo diferente do testado. A diferença acaba sendo que você não se utiliza de mocks (o que pode até ser algo bom).

No Rails, os testes de unidade testam os modelos (lembra deles?). Vamos criar um modelo para fazer um teste simples do Rails.

Primeiro, abra o console (ou prompt) e vá ao diretório raíz do seu projeto. Depois, digite:
ruby script/generate model Pessoa nome:string data_nascimento:date salario:decimal

Explicando: a pasta script contém várias utilidades para ajudá-lo na criação da sua aplicação. O script "generate" gera o que você mandar ele gerar, seja um modelo, um controlador, migração ou scaffold. Explicarei tudo isso em posts futuros.

O parâmetro model serve para especificar que o que você está gerando é um modelo. Pessoa diz qual é o nome do modelo. Os outros definem os atributos do mesmo (e da respectiva tabela).

Agora, digite
rake db:migrate


Quando você gera um modelo, também gera uma migração (na pasta db/migrate) respectiva àquele modelo. A migração gera a tabela no banco de dados, com o comando acima. Bem mais simples que digitar todo o SQL, não?

Junto com o modelo gerado, também é criado um teste de unidade na pasta test/unit. Abra-o. Ele já possui uma asserção, que sempre retornará verdadeiro. Digite
rake

No console e você verá um sinal de sucesso. Não é o que queremos, por enquanto.

Abra o teste (em test/unit/pessoa_test.rb). Apague as linhas


test "the truth" do
  assert true
end

Agora vamos começar a testar, mesmo. Por enquanto, não temos nenhuma funcionalidade especial em mente, então vamos começar com uma interessante. O usuário só pode se cadastrar se ele digita um nome.

Onde havia o código anterior, digite.


def test_usuario_cadastrou_um_nome
  pessoa = Pessoa.new
  pessoa.salario = 1000.00
  pessoa.data_nascimento = Date.civil(1989,11,9)
  assert !pessoa.save
end

Esse código é bem simples. Se vocês não sabem o que é "def", voltem ao Ruby antes de estudar Rails, é simplesmente a definição de um método. Todos os métodos da classe que começam com "test" são o teste, em si. Todas as asserções dentro do teste serão analizadas, e caso todas sejam válidas, o teste contará como um sucesso.

As três linhas seguintes são óbvias: estamos declarando uma pessoa e definindo um salário e uma data de nascimento para ela.

A linha "assert !pessoa.save" é a chave do teste. Assert é uma asserção (que eu tanto falei há algumas linhas e ainda não expliquei). Asserções validam o que há dentro delas. Se realmente for algo válido, a asserção retorna um sucesso. Senão, ela pára o teste e avisa que houve uma falha.

A asserção mais simples é "assert", que verifica se o que está dentro dela é true.

O que nos leva à questão: o método pessoa.save retorna um boolean?

A resposta é sim. Sempre que o Rails tenta salvar um registro no banco de dados, ele retorna true caso ele tenha conseguido e false caso não tenha conseguido. Nesse caso, nós queremos que retorne false, porque não queremos que ele consiga salvar o registro, já que o nome da pessoa não foi definido. Por isso o "!" antes de pessoa.save, ele simboliza "não" em muitas linguagens de programação, inclusive Ruby.

Vá no console e digite rake novamente. Você vai ver o teste falhar.

"Tudo isso para um teste falho? Mas não queríamos fazer um programa, afinal de contas?"

Novamente, estamos testando ANTES de fazer o código que vai validar o teste. Isso é o que chamamos de Test-Driven Development, ou Desenvolvimento Orientado a Testes. Sempre que você for programar, primeiro faz os testes automatizados, roda-os, vê falharem, e faz os códigos o mais simples possíveis para passarem nos testes.

Dessa forma, você terá um sistema simples, legível e com o mínimo de bugs.

Agora vamos fazer o teste retornar um sucesso.

Abra o arquivo app/models/pessoa.rb. Insira dentro da classe a linha


validates_presence_of :nome


Essa linha é bem óbvia. É um validador, e vai verificar se o usuário lembrou de digitar seu próprio nome. Não se preocupe com isso, por enquanto, também vou explicar em posts futuros.

Rode o rake de novo e veja o teste retornar um sucesso. Parabéns! Você fez um teste de unidade!

No próximo post, explicarei fixtures e como elas podem melhorar seus testes.

sexta-feira, 4 de dezembro de 2009

Testando seus modelos no Rails - parte 1

Vou começar com uma citação do livro Programando Rails "A Bíblia", de Obie Fernandes. A citação é de "Wilson":
Escrever aplicações sem testes faz de você uma pessoa má, incapaz de amar

Exagero, certo? É... talvez não. Rails foi feito com testes em pensamento. Os desenvolvedores testam incansavelmente todas as funcionalidades, você não pode submeter um código novo sem um respectivo teste funcional ou de unidade. Por isso o framework conta com uma biblioteca de testes poderosa, a Test::Unit, da família xUnit, muito usada em várias linguagens, incluindo .NET, Java e C++.

Mas testar pra quê?

Verdade seja dita, a pergunta deveria ser "por que não testar?". Hoje, com a ascenção dos métodos ágeis de programação, testes automatizados têm se tornado importantíssimos. Algumas metodologias, como XP (eXtreme Programming) obrigam você a programar os testes ANTES de programar a aplicação, em si.

Agora você deve estar pensando "mas você não respondeu à pergunta. Para quê testar? Eu programo muito bem, confio no meu código, ele não vai dar erro".

Vai. Mesmo com todos os testes automatizados e profissionais da qualidade de software, o usuário final VAI encontrar erros no programa, e vai se irritar com isso ou se aproveitar disso.

Por que programar testes antes de programar a aplicação? Não faz sentido, o que vai ser testado?

Na verdade, adotar essa ideia de programar primeiro os testes já facilitou a vida de muita gente. Programando os testes, você saberá o que o programa deverá fazer (pois você terá nos testes os resultados que devem ser retornados); o teste funcionará como uma documentação rápida das capacidades do programa/ acúmulo de erros no decorrer do projeto costumam ocorrer (o que torna as coisas mais difíceis de serem rastreadas e corrigidas), mas se você fizer testes serão detectados mais cedo; e, além de tudo isso, há de se lembrar que Ruby é uma linguagem interpretada. Se você não executar testes, como saber se você não cometeu nenhum erro de sintaxe?

Serei sincero. Eu não costumo programar testes antes de programar a aplicação. Mas isso já me fez recomeçar projetos inteiros do zero por excesso de bugs. Então, acredite quando eu digo que testes automatizados são muito úteis para tornar as coisas menos complexas.

Ok, agora vamos começar com a mão na massa. Abra a pasta /test do seu projeto. Você verá as seguintes pastas e arquivo:





Para quem está acostumado com nomenclaturas de testes automatizados, os nomes mudam um pouco. Por partes:

  • Fixtures - Essas são as vilãs heróicas. Muita gente não gosta de fixtures, mas a utilidade delas é imensa. Fixtures são dados escritos como um arquivo YML (que explicarei na próxima parte) que serão carregados pelo banco de dados de teste para executar qualquer teste que você queira. Cuidado ao referenciar uma fixture dentro da outra: nunca se sabe qual é a fixture que será lida pelo banco de dados primeiro.

  • Functional - Functional tests, no Rails, são bem semelhantes a functional tests normais, mas são focados em controladores. Esse tipo de teste deve capturar os requerimentos do usuário e deve cuidar para que esses requerimentos sejam preenchidos. Imagine-se fazendo casos de uso, muitos e muitos casos de uso. Quando você finalmente termina... não acontece nada, só tem um monte de bolinhas. No caso de um functional test, você cria testes semelhantes a caso de uso, e faz a aplicação de forma que passe nos testes feitos! Enquanto unit tests testam sob um ponto de vista da programação, functional tests testam sob ponto de vista do usuário. O que quer dizer que você deve ver se o sistema está rodando conforme as necessidades do usuário. Sim, isso quer dizer que eles são essenciais.

  • Integration - Integration tests têm um significado parecido com o tradicional. Permitem a você testar grandes cadeias de código e ver se cada uma das partes do código trabalham bem em conjunto. Provavelmente serão pouco usados, por serem necessários em casos bem específicos e lentos.

  • Performance - É um nome bem sugestivo. Performance tests testam o quanto sua aplicação está demorando para atender aos requisitos, e onde elas mais estão demorando. Bem útil, não?

  • Unit - Unit tests são bem diferentes no Rails com relação à nomenclatura normal. Enquanto normalmente representam testes de funcionalidades isoladas, sob ponto de vista do programador (no sentido de que o programador imagina determinada função ou objeto e vai testá-la), no Rails representam Functional Tests de Modelos. Apenas isso. Você pode referenciar um Modelo num teste de outro sem problemas. É meio confuso usar o termo "Unit test" para um teste que, na verdade, é funcional. Mas se você ignorar isso vai viver bem. :)


Os testes de Rails são executados com o banco de dados site_test (ou comercio_test, ou hotel_test, ou qualquer nome que você tenha colocado na aplicação). É bem difícil fazer um teste que não envolva banco de dados, então não é recomendável.

No próximo post eu ensinarei a programar os testes e a executá-los.

terça-feira, 1 de dezembro de 2009

Aplicações Rails

Agora que o Rails está pronto para trabalhar, vamos estudar a estrutura básica de uma aplicação Rails.

Antes de mais nada, você precisa aprender a CRIAR uma aplicação Rails.

Abra seu prompt de comando (se for usuário de Windows) ou terminal (se for usuário de Linux) e digite:
rails site

Isso vai criar toda a estrutura básica da sua aplicação. O primeiro parâmetro apenas avisa que o que você quer é criar uma aplicação Rails. O segundo diz o nome da aplicação.

Agora que a estrutura está criada, vou explicar alguns conceitos para que você possa entender o que significa cada uma das pastas. Certos conceitos, como bancos de dados, deveriam ser conhecidos antes de você querer se aprofundar em desenvolvimento web, então não vou me aprofundar neles. Mas existem princípios que não são amplamente conhecidos, como os já citados DRY e REST.

Antes de mais nada, vamos ter consciência do que é MVC. É um padrão de arquitetura que tenta dividir as responsabilidades da aplicação em três divisões: uma delas se encarregará dos dados (Model, ou Modelo); a outra do layout e apresentação (View, ou Visualização) e o último serve de "cola" entre os dois, processando eventos e entradas de usuário, enviando-os para modelos, ou pegando os dados do modelo e aplicando-os às visualizações (o Controller, ou Controlador).

MVC é a base do Rails. Todo o framework foi projetado e construído pensando em torná-lo o mais compatível possível com este padrão. E o melhor de tudo: conseguiu. Vamos ver como logo, logo.

O DRY (Seco) é outro elemento importantíssimo para o Rails, e significa algo tão simples quanto o que o nome indica: Don't Repeat Yourself (Não Repita a Si Mesmo). Como ficaria muito estranho chamá-lo de NRaSM, continuemos chamando de DRY. O que o DRY quer dizer é que você deve, ao máximo, evitar fazer o mesmo código duas ou mais vezes, o que torna a manutenção do site muito mais fácil, já que você não vai precisar se preocupar em esquecer de alterar um código duplicado.

Isso é quase sempre possível. Quase porque o sistema de herança do Rails não é tão bom, então se você tiver um sistema com dois tipos de usuário, digamos, Professor e Aluno, você vai precisar fazer o mesmo código de autenticação para ambos. É algo que considero um defeito do Rails e espero que seja corrigido em versões futuras.

Se eu estiver errado e houver uma forma de fazer isso, por favor, avisem-me.

E, finalmente, o REST, o conceito mais complicado dos três. Representational State Transfer (Transferência de Estado Representacional) se refere a um conjunto de recursos (geralmente, páginas HTML, mas pode ser RSS, XML, imagens, ou qualquer outra coisa que vier à sua cabeça) onde realizamos ações CRUD (Create, Read, Update, Destroy; ou Criar, Ler, Atualizar e Destruir). No fim das contas, todas as ações em uma aplicação de banco de dados podem se resumir a essas, por isso REST é tão útil em Rails (que é um framework web para aplicações focadas em bancos de dados, afinal).

Com esses conceitos explicados, vamos à aplicação.

Abrindo o diretório da sua aplicação, você verá essas pastas:











Explicarei o que cada uma significa.
  • app armazena tudo diretamente relacionado à aplicação. Ou seja: os Modelos, as Visualizações e os Controladores (entendeu agora? Hã? Hã?). Se você abri-la, você verá uma pasta para cada uma dessas divisões e uma pasta helper. Esta pasta serve apenas para armazenar funções que puderem ser usadas em qualquer parte da aplicação. Não se preocupe muito com ela.
  • config armazena dados sobre a inicialização da aplicação (boot.rb), sobre o gerenciador de banco de dados usado (database.yml), sobre os ambientes de desenvolvimento (environment.rb) e sobre as rotas (routes.rb). Não se preocupem com nada disso, explicarei em posts futuros.
  • db armazena tudo o que está relacionado ao banco de dados. Também explicarei como mais tarde.
  • doc armazena a documentação gerada com o comando rake doc:app. Também explicarei mais tarde.
  • lib armazena qualquer módulo do Ruby que você queira usar na sua aplicação.
  • log armazena o log do servidor. Simples assim.
  • public armazena todas as informações estáticas da aplicação, incluindo HTML estática, CSS, imagens e Javascript.
  • script armazena os scripts utilitários do Rails, como um script para rodar o servidor e outro para criar um novo modelo ou um novo controlador. Explicarei mais tarde (sim, eu sei que tô deixando muita coisa para mais tarde, mas o post JÁ ESTÁ grande assim).
  • test armazena os testes de unidades que serão usados na aplicação. Muito útil para quem se utiliza de desenvolvimento ágil. Adivinha só? Vou explicar mais tarde.
  • tmp armazena o cache e as sessões da aplicação.
  • vendor armazena quaisquer plugins instalados.

Como podem ver, o Rails organiza ao máximo sua aplicação. Imagine-se programando numa aplicação ASP: você mesmo teria que criar as pastas e os arquivos, e geralmente o faria de forma caótica. Depois de um tempo, você já não saberia mais encontrar o que quer que seja na aplicação.

Com Rails, como você pode ver, encontrar tudo fica mais fácil. Especialmente quando ele tem um utilitário para gerar a documentação.

Isso é tudo por hoje. No próximo post, explicarei scaffold.

domingo, 29 de novembro de 2009

rails NovoUsuario -d sqlite3

Creio que antes de começar a ensinar o que são essas siglas que mencionei no último post, é mais importante dizer como iniciar e configurar o Ruby on Rails.

Mesmo sendo usuário de Windows, recomendo a você ler o tutorial para os usuários de Ubuntu, pois eu explico alguns conceitos que podem parecer novos a você.

Usuários de Ubuntu



Se você é usuário de Ubuntu, como eu, instalar tudo é fácil: basta instalar os pacotes ruby-full e build-essential, com esse comando:
sudo aptitude install ruby-full build-essential

Isso vai instalar toda a base do Ruby (a linguagem de programação usada no Ruby on Rails), como o irb (console do Ruby), rdoc (gera documentação a partir do código Ruby) e, principalmente, o RubyGems (gerenciador de pacotes do Ruby).

Você não vai instalar nenhuma extensão do Ruby através do apt ou do Synaptic (ou através de instaladores executáveis, no caso do Windows), e só vai compilar do código se não existir versão no repositório do Ruby. Você deve, ao máximo, instalar todas as extensões, incluindo o Rails, através do RubyGems. Como fazer isso? Com o comando gem.

Primeiro, atualize o RubyGems:
sudo gem update --system

Depois, instale o Rails, incluindo todas as dependências:
sudo gem install rails -y

O -y significa a mesma coisa que --include-dependencies, não importa qual dos dois você vai usar.

Depois de instalado o Rails, você deve instalar o SQLite3:
sudo aptitude install sqlite3

E o driver para Ruby:
sudo gem install sqlite3-ruby

Estou usando SQLite3 como exemplo porque é um gerenciador de Banco de Dados muito leve e de fácil uso, ótimo para o aprendizado do Ruby, mas nada recomendado para aplicações sérias. Nesse caso, o Ruby também tem drivers para MySQL, PostgreSQL, entre outros SGBD's. Ensinarei a instalá-los em posts futuros.

Pronto, seu ambiente Rails está pronto para ser usado.

Usuários de Windows



Antes de mais nada: recomendei que lesse a seção anterior, mesmo sendo usuário de Windows. Você deve ter visto um termo que talvez tenha soado estranho: "gerenciador de pacotes". O que seria isso?

Um gerenciador de pacotes é apenas um programa que instala, atualiza e remove "pacotes" (aplicações pré-compiladas). Ou seja: você não precisa ficar se preocupando em acessar o site do Rails sempre que uma nova versão sair, basta atualizar o RubyGems. Simples, não?

O Rails não tem uma performance tão boa no Windows quanto no Linux, e isso é perceptível. É muito mais fácil integrá-lo com Apache no Linux e no Mac OS, inclusive. Mas, se você está apenas aprendendo, o Windows pode ser uma boa opção, porque o servidor de testes do Rails (o WEBrick) não precisa ser configurado.

Primeiro, você deve baixar o binário do Ruby 1.8 em http://www.ruby-lang.org/pt/downloads/
Facilmente localizável, basta baixar o One-Click Installer. Não baixe a versão 1.9. As versões com a segunda numeração ímpar são sempre experimentais, e servem apenas para testar as funcionalidades que poderão ser implementadas na versão seguinte (que, no caso, será a 2.0). Por isso, o Rails não tem suporte ao Ruby 1.9.

Depois, baixe o SQLite. Procure em http://www.sqlite.org/download.html a seção Precompiled Binaries For Windows. Baixe os arquivos sqlite-3_6_20.zip e sqlitedll-3_6_20.zip e descompacte-os para C:\Ruby\bin (ou qualquer outro diretório onde o Ruby esteja instalado). Acredite, tudo fica mais fácil se você deixá-los nesse diretório.

Depois, instale as gems como explicado na seção de usuários de Linux, abrindo o prompt de comando e digitando:
gem update --system
gem install rails -y
gem install sqlite3-ruby

Repare que no Windows você não digita o sudo.

Se esses comandos não funcionarem, digite
cd c:\Ruby\bin

E tente de novo.


Pronto, agora o Rails está instalado e você pode começar a usá-lo.

sábado, 28 de novembro de 2009

Introdução

Comecei a programar com Rails há pouco tempo, ainda esse ano. Creio que eu não tenha completado um semestre de uso.

Ainda assim, aprendi a usar tantos recursos, de forma tão rápida e limpa, que fiquei impressionado. Os códigos são curtos, simples, e inteligíveis; usar Ajax com Rails é tão fácil quanto não usar; a organização torna tudo mais fácil de manter e consertar; usar diferentes SGBD's é mais fácil que instalar uma aplicação pelo Synaptic, entre diversos outros milagres do DRY, REST e MVC, que explicarei mais tarde.

É incrível a curva de aprendizagem desse framework. Em poucas semanas estava conseguindo usá-lo, e quanto mais aprendo sobre ele, mais fácil ele se torna, ao contrário da maioria das bibliotecas e API's.

Não, não tenho toda uma carga de experiência para ensinar qualquer coisa. Mas tenho experiẽncia para ajudar iniciantes em caminhos que eu sofri MUITO para encontrar soluções. DRY e REST são ótimos, mas às vezes é difícil encontrar uma solução assim sem ajuda.

E eu espero aprender mais do que pretendo ensinar. O ensino é um aprendizado, afinal.