Ruby on Rails 2.1 - Teste de Unidade
Introdução
Antes de prosseguir, vamos dar uma olhada rápida em algumas definições -
o Tests- São aplicativos de teste que produzem resultados consistentes e provam que um aplicativo Rails faz o que se espera que faça. Os testes são desenvolvidos simultaneamente com o aplicativo real.
o Assertion- Esta é uma linha de código que avalia um objeto (ou expressão) quanto aos resultados esperados. Por exemplo - este valor é = aquele valor? Este objeto é nulo?
o Test Case- Esta é uma classe herdada de Test :: Unit :: TestCase contendo uma estratégia de teste composta por testes relacionados ao contexto.
o Test Suite- Esta é uma coleção de casos de teste. Quando você executa um conjunto de testes, ele, por sua vez, executa cada teste que pertence a ele.
Teste de Rails
Quando você executa o script helper script / generate para criar controladores e modelos , o Rails gera um framework para testes unitários e funcionais. Você pode obter uma cobertura de teste muito boa preenchendo a estrutura com testes para a funcionalidade que você escreve. Existem dois pontos importantes para testar em uma aplicação Rails -
Testando os Modelos
Testando os controladores
Este tutorial irá abranger ambos os testes resumidamente. Então, vamos criar um testapp para entender o conceito.
C:\ruby> rails -d mysql testapp
Configuração do banco de dados
Até agora, usamos apenas o banco de dados de desenvolvimento de aplicativos Rails, mas agora você precisa ter certeza de que o banco de dados de teste também foi criado e as seções apropriadas de seu arquivo config / database.yml estão configuradas corretamente.
Vamos criar bancos de dados de desenvolvimento e teste da seguinte maneira -
mysql> create database testapp_test;
Query OK, 1 row affected (0.01 sec)
mysql> create database testapp_development;
Query OK, 1 row affected (0.01 sec)
mysql> use testapp_test;
Database changed
mysql> grant all privileges on testapp_test.*
to 'root'@'localhost' identified by 'password';
Query OK, 0 rows affected (0.00 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
Configurando database.yml
Configure seu config / database.yml da seguinte maneira -
development:
adapter: mysql
encoding: utf8
database: testapp_development
username: root
password: password
host: localhost
test:
adapter: mysql
encoding: utf8
database: testapp_test
username: root
password: password
host: localhost
production:
adapter: mysql
encoding: utf8
database: testapp_production
username: root
password: password
host: localhost
Gerar Migração
Suponha que você tenha uma tabela contendo livros, incluindo seus títulos, preço e uma pequena descrição. A migração a seguir configura esta tabela -
testapp > ruby script/generate migration books
Agora modifique o arquivo testapp / db / migrate / 20080616170315_books.rb da seguinte maneira -
class Books < ActiveRecord::Migration
def self.up
create_table :books do |t|
t.string :title, :limit => 32, :null => false
t.float :price
t.text :description
t.timestamp :created_at
end
end
def self.down
drop_table :books
end
end
Agora execute a migração da seguinte maneira -
testapp > rake db:migrate
Isso vai criar bookstabela no banco de dados testapp_development. Depois disso, precisamos configurar seu banco de dados de teste usando o comando rake da seguinte forma -
C:\ruby\testapp > rake db:test:clone_structure
Isso clonará o banco de dados testapp_development no banco de dados testapp_test . Isso significa que tudo o que você tem no banco de dados de desenvolvimento, agora também terá os mesmos dados no banco de dados de teste.
Modelos de teste
Quando você gera um modelo com o script de geração, o Rails também gera um script de teste de unidade para o modelo no diretório de teste. Ele também cria um fixture , um arquivo YAML contendo dados de teste a serem carregados no banco de dados testapp_test. Estes são os dados com os quais seus testes de unidade serão executados -
testapp > ruby script/generate model Book
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/book.rb
create test/unit/book_test.rb
create test/fixtures/books.yml
create db/migrate
create db/migrate/20080616164236_create_books.rb
Conforme você escreve o código nas classes de modelo, você escreverá testes correspondentes nesses arquivos. Então, vamos criar dois registros de livro de teste usando YAML em test / fixtures / books.yml da seguinte maneira -
perl_cb:
id: 1
title: 'Ruby Tutorial'
price: 102.00
description : 'This is a nice Ruby tutorial'
java_cb:
id: 2
title: 'Java Programming'
price: 62.00
description : 'Java Programming for the beginners'
Agora vamos substituir o código existente no arquivo de teste de unidade do livro test / unit / book_test.rb pelo seguinte código -
require File.dirname(__FILE__) + '/../test_helper'
class BookTest < ActiveSupport::TestCase
fixtures :books
def test_book
perl_book = Book.new :title => books(:perl_cb).title,
:price => books(:perl_cb).price,
:description => books(:perl_cb).description,
:created_at => books(:perl_cb).created_at
assert perl_book.save
perl_book_copy = Book.find(perl_book.id)
assert_equal perl_book.title, perl_book_copy.title
perl_book.title = "Ruby Tutorial"
assert perl_book.save
assert perl_book.destroy
end
end
Finalmente, execute o método de teste da seguinte maneira -
testapp > ruby test/unit/book_test.rb
Aqui está o resultado da execução do caso de teste de sucesso -
testapp > ruby test/unit/book_test_crud.rb
Loaded suite ./test/unit/book_test
Started
.
Finished in 0.0625 seconds.
1 tests, 4 assertions, 0 failures, 0 errors
Vamos analisar o que aconteceu aqui -
O método BookTest começa criando um novo objeto Book usando o título e outros campos do primeiro registro no texto fixture / books.yml. O objeto resultante é armazenado na variável de instância perl_book.
A primeira asserção testa se o salvamento do objeto Book foi bem-sucedido.
Em seguida, o objeto de livro é recuperado usando o método find e armazenado em outra variável de instância chamada perl_book_copy. O sucesso dessa recuperação é testado na próxima asserção, que compara os títulos de ambos os objetos de livro. Neste ponto, testamos a capacidade de criar e ler um registro de banco de dados.
A solução testa a atualização atribuindo um novo título ao objeto armazenado em perl_book e, a seguir, afirma que o salvamento da alteração foi bem-sucedido.
Finalmente, a capacidade de destruir um objeto Livro é testada.
É assim que podemos testar nossos modelos Rails.
Testando os controladores
O teste do controlador também é conhecido como functional testing. O teste funcional testa o seguinte tipo de funcionalidade dos controladores -
- A resposta foi redirecionada conforme o esperado?
- O modelo esperado é renderizado?
- O roteamento está conforme o esperado?
- A resposta contém as tags esperadas?
O framework Rails suporta cinco tipos de solicitações -
- get
- post
- put
- head
- delete
Para escrever um teste funcional, você precisa simular qualquer um dos cinco tipos de solicitação HTTP que seu controlador processará.
Os tipos de solicitação "get" e "post" são os mais comumente usados em testes de controlador. Todos esses métodos levam quatro argumentos -
- A ação de um controlador
- Um hash opcional de parâmetros de solicitação
- Um hash de sessão opcional
- Um hash flash opcional
Neste tutorial, veremos como usar getmétodo para testar nosso controlador. Você pode testar o restante dos métodos de maneira semelhante.
Quando você gera um controlador com generate, o Rails cria um script de teste funcional para o controlador da seguinte maneira -
testapp > ruby script/generate controller Book
exists app/controllers/
exists app/helpers/
create app/views/book
exists test/functional/
create app/controllers/book_controller.rb
create test/functional/book_controller_test.rb
create app/helpers/book_helper.rb
Conforme você escreve o código nas classes do controlador, você escreverá testes correspondentes nesses arquivos. Antes disso, vamos definir nossa lista de funções do controlador , mostrar e pesquisar dentroapp/controllers/book_controller.rb como segue -
class BookController < ApplicationController
def list
@book_pages, @books = paginate :books, :per_page => 10
end
def show
@book = Book.find(params[:id])
end
def search
@book = Book.find_by_title(params[:title])
if @book
redirect_to :action => 'show', :id => @book.id
else
flash[:error] = 'No such book available'
redirect_to :action => 'list'
end
end
end
NOTE - Você precisaria de dois modelos de visualizações para showe método de lista . Você pode definir essas visualizações e testá-las, mas agora, continuaremos sem definir essas visualizações.
Agora vamos reutilizar nosso dispositivo de teste que está no test/fixtures/books.yml arquivo da seguinte forma -
perl_cb:
id: 1
title: 'Ruby Tutorial'
price: 102.00
description : 'This is a nice Ruby tutorial'
java_cb:
id: 2
title: 'Java Programming'
price: 62.00
description : 'Java Programming for the beginners'
Adicione os seguintes test_search_book e test_search_not_found métodos para test / functional / book_controller_test.rb para testar a funcionalidade de ação de busca do Controlador do Livro.
require File.dirname(__FILE__) + '/../test_helper'
require 'book_controller'
# Re-raise errors caught by the controller.
class BookController
def rescue_action(e)
raise e
end
end
class BookControllerTest < Test::Unit::TestCase
fixtures :books
def setup
@controller = BookController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_search_book
get :search, :title => 'Ruby Tutorial'
assert_not_nil assigns(:book)
assert_equal books(:perl_cb).title, assigns(:book).title
assert_valid assigns(:book)
assert_redirected_to :action => 'show'
end
def test_search_not_found
get :search, :title => 'HTML Tutorial'
assert_redirected_to :action => 'list'
assert_equal 'No such book available', flash[:error]
end
end
Agora execute seus casos de teste da seguinte maneira -
testapp > ruby test/functional/book_controller_test.rb
Ele fornece a seguinte saída -
Loaded suite test/functional/book_controller_test
Started
..
Finished in 0.422 seconds.
2 tests, 7 assertions, 0 failures, 0 errors
Vamos analisar o que aconteceu aqui -
O método de configuração é um método padrão para criar objetos de controlador, solicitação e resposta. Eles seriam usados pelo Rails internamente.
O primeiro método de teste test_search_book gera umgetsolicitação para a ação de pesquisa, passando um parâmetro de título .
As próximas duas asserções verificam se um objeto Book foi salvo em uma variável de instância chamada @book e se o objeto passa por quaisquer validações Active Record que possam existir.
A asserção final dentro do primeiro método testa que a solicitação foi redirecionada para a ação show do controlador.
O segundo método de teste, test_search_not_found , executa outra solicitação get, mas passa um título inválido
As primeiras asserções testam se um redirecionamento para a ação list foi emitido.
Se as afirmações anteriores forem aprovadas, deve haver uma mensagem no hash flash que você pode testar com assert_equal ..
Para obter mais informações sobre Assertions, consulte a Documentação Padrão do Rails .
Usando Rake para Testes
Você pode usar rakeutilitário para testar seus aplicativos. Abaixo está uma lista de alguns comandos importantes.
$rake test - Teste todos os testes de unidade e testes funcionais (e testes de integração, se houver).
$rake test:functionals- Execute todos os testes funcionais.
$rake test:units - Execute todos os testes de unidade.
$rake test:integration - Execute todos os testes de integração.
$rake test:plugins - Execute todos os testes em ./vendor/plugins/**/test.
$rake test:recent - Executar testes para modelos e controladores que foram modificados nos últimos 10 minutos -
$rake test:uncommitted - Para projetos no Subversion, execute testes para as mudanças que ocorreram nos modelos e controladores desde o último commit -