Test-Driven Development no Rails: Unit mauricio052/Engenharia de Software I/TDD/Test...Test-Driven Development

  • View
    213

  • Download
    0

Embed Size (px)

Text of Test-Driven Development no Rails: Unit mauricio052/Engenharia de Software I/TDD/Test...Test-Driven...

  • Test-Driven Development no Rails: Unit Tests

    11/05/07

    Tags: , Ruby, Ruby on Rails, TDD, Teste Unitrio, Unit Tests

    Todo mundo fala que Test-Driven Development aumenta sua produtividade, reduz a quantidade de erros do seu cdigo e deixa todo mundo mais feliz. O quem ningum fala como fazer isso, quando voc no conhece nada de testes. Por isso, resolvi escrever este texto, mostrando o pouco que aprendi nas ltimas semanas sobre esse tema.

    Test-Driven Development (TDD) Desenvolvimento Orientado a Testes ou Desenvolvimento Guiado por Testes uma tcnica de desenvolvimento de software onde primeiro so criados os testes e somente depois escrito o cdigo necessrio para passar por eles. Dessa maneira, voc escrever cdigos melhores e, o que mais importante, muito mais rapidamente. Veja como o ciclo de TDD, segundo o livro Test-Driven Development by Example, de Kent Back (ISBN-0321146530):

    1. Crie um teste: Cada nova funcionalidade deve comear com um teste escrito. Este teste deve falhar antes da funcionalidade ser implementada. Voc deve conhecer claramente os requisitos e especificaes da funcionalidade.

    2. Execute todos os testes: Voc saber que a rotina de testes est funcionando corretamente e que o novo teste no passou sem que o teste da funcionalidade tenha sido implementado.

    3. Escreva o cdigo: Escreva o cdigo que ir passar naquele teste que voc criou na etapa anterior, sem se preocupar em torn-lo elegante/otimizado. muito importante que o cdigo implementado reflita somente o teste escrito.

    4. Execute novamente todos os teste: Se todos os testes passarem, voc ter certeza que o cdigo atende todos os requisitos testados e que esta nova funcionalidade no afetou outras partes do sistema.

    5. Refatore o cdigo: Agora voc pode "limpar" o cdigo, se for necessrio. Lembre-se de executar os testes constantemente durante esta etapa, pois s assim voc saber se o sistema no foi modificado de maneira incorreta, gerando erros.

    Os testes, quando devidamente implementados, oferecem uma certa "garantia" de que a aplicao est funcionando da maneira como deveria.

    TDD no Rails

    Este texto no tem a pretenso de ser o "guia definitivo" de TDD; ao invs disso, voc ver uma abordagem simples e direta do assunto, utilizando Ruby on Rails. No irei explicar detalhadamente como desenvolver em Rails; para isso voc tem outras fontes um tanto quanto completas.

    O que um teste? Teste um mtodo que contm asseres segundo o dicionrio Houaiss, assero significa "afirmao categrica" e que representam um cenrio de testes em particular. Um teste s passar caso todas as asseres sejam verdadeiras.

  • No Ruby, um teste um mtodo iniciado por "test"; assim, voc pode nomear seu mtodo como "test_", "testing_", "testando_", e por a vai!

    O Rails trabalha com alguns tipos diferentes de testes. Existem os testes unitrios que so responsveis pelos testes de modelos; existem os testes funcionais, responsveis por testar os controllers; e, por ltimo, temos os testes de integrao, responsveis por testar mltiplas camadas de seu aplicativo e a integrao entre elas.

    O teste unitrio ser, provavelmente, o primeiro lugar onde voc ir trabalhar em qualquer projeto. Isso acontece porque no preciso escrever muito cdigo vou alm e digo que no preciso escrever nenhum cdigo para se criar tais testes, a no ser o prprio teste.

    Quando estamos fazendo TDD, importante que todos os seus testes iniciais no passem na validao, pois voc precisa identificar os itens a serem validados para depois corrigi-los. Voc deve tambm criar pelo menos um teste que passe na validao.

    Nosso exemplo

    Ns vamos criar um sistema de blog muito mais poderoso que o Wordpress :P totalmente feito em Rails. Ento, a primeira coisa que temos que fazer pensar nos requisitos de nosso projeto. Isso importante, pois permite ter uma viso melhor do que precisa ser feito. Obviamente, podemos ajustar tais requisitos ao longo do tempo. A princpio, nosso blog deve:

    permitir configuraes sobre o autor (nome, email, etc) criar posts com resumo permitir que usurios postem comentrios, informando email, nome e website

    Completo, no? :)

    Para comear, vamos criar nossa aplicao. Digite o comando rails blog. Nosso projeto ser criado e a lista dos arquivos ser exibida. Iremos, ento, criar nosso banco de dados MySQL, neste exemplo tanto de desenvolvimento quanto de testes. Se voc no se sente confortvel com a linha de comandos, faa da maneira como est acostumado.

    ~$ mysqladmin -u root create blog_development ~$ mysqladmin -u root create blog_test

    Abra o arquivo "config/database.yml" e insira o usurio e senha que tero acesso aos bancos de dados. Meu arquivo se parece com isso:

    development: adapter: mysql database: blog_development username: root password: socket: /var/run/mysqld/mysqld.sock test: adapter: mysql

  • database: blog_test username: root password: socket: /var/run/mysqld/mysqld.sock production: adapter: mysql database: blog_production username: root password: socket: /var/run/mysqld/mysqld.sock

    muito importante que voc defina 2 bancos diferentes para desenvolvimento e testes, uma vez que o banco de dados "testes" apagado quando estamos testando nossa aplicao.

    Quando nosso desenvolvimento orientado a testes, voc inicialmente s cria os modelos e, logo depois, parte para os testes. Controllers? No, agora. Voc s ir cri-los muito mais frente. Vamos trabalhar inicialmente no modelo "usurio".

    ~/blog$ script/generate model User exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/user.rb create test/unit/user_test.rb create test/fixtures/users.yml create db/migrate create db/migrate/001_create_users.rb

    O Rails nos permite trabalhar com DDLs muito facilmente atravs das migrations. Ento, neste texto no iremos lidar com SQL diretamente, mas Ruby.

    Abra o arquivo "db/migrate/001_create_users.rb". Nossa tabela de usurios ter os campos "name", "email" e "password". Sua migrao dever ser algo como:

    class CreateUsers < ActiveRecord::Migration def self.up create_table :users do |t| t.column :name, :string, :nil => false t.column :email, :string, :nil => false t.column :password, :string, :nil => false end end def self.down drop_table :users end end

    Execute o comando rake db:migrate para criar a tabela "users".

    ~/blog$ rake db:migrate (in /home/nando/blog) == CreateUsers: migrating ===================================================== -- create_table(:users)

  • -> 0.0035s == CreateUsers: migrated (0.0037s) ============================================

    Com a tabela criada, podemos meter a mo na massa!

    Abra o arquivo "test/unit/user_test.rb", que foi gerado automaticamente quando criamos nosso modelo. Uma das vantagens de se desenvolver em Rails justamente esta; to simples de se criar testes para uma aplicao, com arquivos criados automaticamente, que voc deve se sentir envergonhado de no faz-lo.

    Este arquivo possui uma nica assero chamada test_truth. Apesar de parecer intil, ela ajuda a corrigir algumas configuraes do ambiente, como quando o banco de dados de teste no existe, por exemplo.

    require File.dirname(__FILE__) + '/../test_helper' class UserTest < Test::Unit::TestCase fixtures :users # Replace this with your real tests. def test_truth assert true end end

    Para rodarmos nossos testes unitrios, devemos executar o comando rake test:units. O Ruby ir executar os testes unitrios e receberemos uma resposta como esta:

    Started . Finished in 0.03095 seconds. 1 tests, 1 assertions, 0 failures, 0 errors

    Esta resposta bastante direta e fcil de entender. Cada ponto exibido na tela (logo abaixo da linha "Started") representa um teste que passou. Temos tambm uma linha que nos diz que foi executado 1 teste, com 1 assero, mas que no retornou erro ou falha.

    O teste que vem por padro no faz muita coisa, ento vamos criar o nosso! Nosso primeiro modelo a ser testado o User. Alguns testes possveis so:

    nome, email e senha so obrigatrios a senha deve ter no mnimo 6 caracteres o e-mail nico

    Podemos escrever um teste genrico para ver se o usurio criado quando no passamos nenhuma informao.

    def test_should_be_invalid user = User.create assert !user.valid?, "User shouldn't be created" end

  • Primeiro, ns criamos um usurio (User.create) sem passar nenhuma informao. Se nosso modelo tivesse uma validao utilizando os mtodos disponveis do ActiveRecord, o mtodo user.valid? retornaria false e nossa aplicao passaria nos testes. Rodando os testes temos uma surpresa:

    ~/blog$ rake test:units Started F Finished in 0.050156 seconds. 1) Failure: test_should_be_invalid(UserTest) [./test/unit/user_test.rb:8]: User shouldn't be created. is not true. 1 tests, 1 assertions, 1 failures, 0 errors rake aborted!

    Alguma coisa no est funcionando direito! Nosso teste deveria receber false do mtodo valid?, o que no aconteceu. No se preocupe em fazer o teste passar. Lembre-se que antes devemos criar os outros testes. Vamos, ento, criar cada um dos testes em separado.

    No sei se voc notou, mas ficou complicado entender a condio assert !user.valid? no teste que criamos. Para estes casos, podemos utilizar helpers, semelhantes ao que utilizamos nas views, mas que aqui so especficos para os testes. Abra o arquivo "tests/test_helper.rb" e adicione os mtodos abaixo:

    def deny(condition, message='') assert !condition, message end def assert_invalid(record, message='') deny record.valid?, message end

    O mtodo deny faz a negativa de assert e o mtodo assert_invalid apenas d uma fora, evitando que tenham