quarta-feira, 19 de novembro de 2008

TDD para o Cartão de Historia - 001

Oi pessoal,


Segue a implementação do primeiro Cartão de Historia utilizando TDD. Eu sou um aprendiz em testes, mas eu espero que este post ajude a entender melhor o processo de desenvolvimento de software direcionado ao comportamento.

O código esta em Ruby. Por que Ruby??? Porque é divertido hahahaha

[Exemplo 1] – [Cartão de Historia]

Como um cliente, quero que o produto seja acompanhado com o valor de desconto para compra a vista, para que eu tenha a visibilidade da diferença monetária do produto a vista ou a prazo.

[Testes] - Template: [ação] [resultado] [objeto]

Mostrar valor do desconto de venda a vista
Mostrar percentual do desconto de venda a vista
Mostrar o valor do produto sem desconto de venda a vista
Mostrar o valor do produto com desconto de venda a vista

Validar valor do produto é maior que o valor do desconto para evitar um valor de desconto maior que o valor de venda

Validar valor do produto maior que zero para evitar produtos sem preço de venda

Mostrar valor do desconto de venda a prazo
Mostrar percentual do desconto de venda a prazo
Mostrar o valor do produto sem desconto na venda a prazo
Mostrar o valor do produto com desconto na venda a prazo


[1]
Para podermos criar os testes unitários do nosso Cartão de Historia vamos primeiramente criar um Model chamado Produto.

ruby script/generate model produto


exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/produto.rb
create test/unit/produto_test.rb
create test/fixtures/produtos.yml
create db/migrate
create db/migrate/001_create_produtos.rb

[2]
O ruby já criou a classe de teste chamada produto_test.rb

O meu primeiro passo foi identificar uma massa de dados para poder realizar o teste desejado. O teste escolhido foi “Mostrar valor do desconto de venda a vista”.

O ruby possibilita a criação de uma estrutura de carga de dados no banco de dados, chamada “Fixtures”. Para o meu teste eu criei dois registros no arquivo “produto.ymx”:

one:
 id: 1
 nome: Ruby OnRails
 preco: 50.00
 desconto: 10

two:
 id: 2
 nome: Java
 preco: 80.00
 desconto: 20

three:
 id: 3
 nome: Ruby OnRails II
 preco: 0.00
 desconto: 10

[3]
Após identificar a necessidade de massa de dados para teste, eu crie um algoritmo para poder executar o primeiro teste (arquivo: produto_test.rb).

# Mostrar o valor do produto com desconto de venda a vista
def test_valor_vista
 produto = Produto.find(1)
 preco = produto.preco
 desconto = produto.desconto
 desconto_perc = Float(desconto) / 100
 valor_desconto = preco * desconto_perc
 preco_vista = preco - valor_desconto
 assert_equal(preco_vista, 45)
end

[4]
Vamos criar o banco de dados para poder executar o teste

Devemos lembrar que o Ruby OnRails vai solicitar a configuração dos databases (database.yml)

development:
 adapter: mysql
 encoding: utf8
 database: tdd_development
 username: root
 password:
 host: localhost

test:
 adapter: mysql
 encoding: utf8
 database: tdd_test
 username: root
 password:
 host: localhost

production:
 adapter: mysql
 encoding: utf8
 database: tdd_production
 username: root
 password:
 host: localhost


create database tdd_development;

create database tdd_test;

create database tdd_production;

[5]
Agora vamos editar o arquivo de definição das tabelas de banco de dados (001_create_produtos.rb).

class CreateProdutos <>
 def self.up 
  create_table :produtos do |t| 
   t.string :nome, :limit => 100, :null => false
   t.decimal :preco, :precision => 6, :scale => 2, :null => false, :default => 0
   t.integer :desconto, :null => false, :default => 0 
   t.timestamps
  end
 end

 def self.down
  drop_table :produtos
 end
end

Realizar a migração dos dados

rake db:migrate



[6]
Vamos executar o teste

rake test:units

Started
......
Finished in 0.125 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

[7]
Agora podemos melhorar o nosso teste e criar o método de negocio.

Código do Teste

# Mostrar o valor do produto com desconto de venda a vista
def test_valor_vista
 produto = Produto.find(1)
 assert_equal(produto.valor_vista, 45)
end

Código do Model

def valor_vista
 preco = self.preco
 desconto = self.desconto
 desconto_perc = Float(desconto) / 100
 valor_desconto = preco * desconto_perc
 preco_vista = preco - valor_desconto
 return preco_vista
end

Executamos o teste de novo

rake test:units

Started
......
Finished in 0.125 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

[8]

Agora vamos implementar o resto dos testes

require File.dirname(__FILE__) + '/../test_helper'

class ProdutoTest <>
 # Replace this with your real tests. 
 #Mostrar valor do desconto de venda a vista 
 def test_valor_desconto 
  produto = Produto.find(1) 
  assert_equal(produto.valor_desconto, 5)
 end 

 #Mostrar percentual do desconto de venda a vista 
 def test_perc_desc 
  produto = Produto.find(1) 
  assert_equal(produto.perc_desc, 10) 
 end 

 #Mostrar o valor do produto sem desconto de venda a vista 
 def test_valor_produto 
  produto = Produto.find(1) 
  assert_equal(produto.valor_produto, 50) 
 end 

 #Mostrar o valor do produto com desconto de venda a vista 
 def test_valor_vista 
  produto = Produto.find(1) 
  assert_equal(produto.valor_vista, 45) 
 end 

 #Validar valor do produto é maior que o valor do desconto para evitar um valor de desconto maior que o valor de venda 
 def test_valida_valor_desconto 
  produto = Produto.find(1) 
  ret = produto.valida_valor_desconto 
  assert_equal(ret, true) 
 end 

 #Validar valor do produto maior que zero para evitar produtos sem preço de venda 
 def test_valor_maior_que_zero_ok 
  produto = Produto.find(1) 
  ret = produto.valor_maior_que_zero 
  assert_equal(ret, true) 
 end 

 #Validar valor do produto maior que zero para evitar produtos sem preço de venda 
 def test_valor_maior_que_zero_erro 
  produto = Produto.find(3) 
  ret = produto.valor_maior_que_zero 
  assert_equal(ret, false) 
 end 
end 

[9] 

O model após a implementação dos testes fica: 

class Produto <>
 def valor_vista 
  preco = self.preco 
  desconto = self.desconto 
  desconto_perc = Float(desconto) / 100 
  valor_desconto = preco * desconto_perc 
  preco_vista = preco - valor_desconto 
  return preco_vista 
 end 

 def perc_desc 
  return self.desconto 
 end 

 def valor_produto 
  return self.preco 
 end 

 def valor_desconto 
  preco = self.preco 
  desconto = self.desconto 
  desconto_perc = Float(desconto) / 100 
  valor_desconto = preco * desconto_perc 
  return valor_desconto 
 end 

 def valida_valor_desconto 
  if (valor_vista <>
   ret = false 
  else 
   ret = true 
  end 
  return ret 
 end 

 def valor_maior_que_zero 
  if (valor_produto <= 0) 
   ret = false 
  else 
   ret = true 
  end 
  return ret 
 end 
end 

[10] 

Devemos lembrar que o processo não é seqüencial e sim interativo e incremental.

[11]

Ficou faltando os testes de venda a prazo, como estamos realizando apenas as operações de venda a vista estes testes não vão ser implementados no momento. Os testes de venda a prazo devem ser encaminhados para um Cartão de Historia que trate da venda a prazo, para que as responsabilidades dos Cartões fiquem coesas.


Mostrar valor do desconto de venda a prazo
Mostrar percentual do desconto de venda a prazo
Mostrar o valor do produto sem desconto na venda a prazo
Mostrar o valor do produto com desconto na venda a prazo




Terminamos.....

Agora vamos implementar os outros Cartões de Historia nos próximos post´s.


Abu

Nenhum comentário: