SlideShare uma empresa Scribd logo
1 de 46
Baixar para ler offline
Aprenda bdd-jogando-dados-ebook
Aprenda bdd-jogando-dados-ebook
Aprenda BDD Jogando Dados!



SEU COMPORTAMENTO É SE DIVERTIR



Primeira Edição
Aprenda bdd-jogando-dados-ebook
Aprenda BDD Jogando Dados!



SEU COMPORTAMENTO É SE DIVERTIR



Primeira Edição



por Valério Farias de Carvalho
Por Valério Farias de Carvalho. Disponibilizado como Creative Commons Atribuição 2.5



Primeira edição: Julho de 2010



Valério Farias
http://www.valeriofarias.com
Twitter: @valeriofarias



Origem da imagem da capa: http://www.flickr.com/photos/missturner/
Aprenda BDD Jogando Dados!




INTRODUÇÃO

Olá entusiasta do Ruby! Olá entusiasta de BDD! Bem vindo a essa jornada linha a linha, teste por teste,
utilizando a técnica do Desenvolvimento Orientado a Comportamento (Behavior Driven Development) em um
projeto muito interessante: Simulação dos dados do jogo War!. Eu escrevi esse pequeno livro para aprender
BDD e RSpec, por isso eu tinha que falar sobre algo simples e de preferência que fosse divertido. Então eu
pensei: Por que não jogar dados! Porque não jogar dados do jogo War! Então aqui está: Aprenda BDD
jogando dados!

A aplicação que nós criaremos juntos usa duas classes: Dice e WarDice. O primeiro capítulo eu começo
construindo o arquivo RSpec da classe Dice e a classe Dice simultaneamente e passo a passo até todos os
testes tornarem-se verdes.

No segundo capítulo eu continuo o desenvolvimento com a classe WarDice, aquela que fará a simulação de
cada dado do jogo war!

Finalmente, no terceiro capítulo eu uso as classes criadas em uma divertida aplicação feita em shoes.

A filosofia desse livro é aprender fazendo coisas divertidas. Em uma palavra: Experimentação. Então eu
espero que você aproveite esse livro simples mas também muito instrutivo.

Os testes usados nesse livro não são uma solução definitiva. Eles são somente possibilidades no meio de
outras. Como eu disse, eu o escrevi para aprender RSpec. Você pode enviar sugestões, clonar o projeto,
modificá-lo e codificá-lo de outra forma. Quem sabe não faremos juntos a versão 2.0 desse livro :).




                                                                                                          7
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir


               O código fonte completo da aplicação você pode encontrar no seguinte endereço: https://github.com/
               valeriofarias/shoes-war-dice/tree

               Agora, apenas leia, codifique, teste, compartilhe e se divirta!




8
Capítulo 1: Fazendo a classe Dice usando BDD




Capítulo 1

             Fazendo a classe Dice usando BDD


             INICIANDO

             Antes de começarmos a programar vamos instalar os pacotes necessários. Primeiro instale o rspec:

               gem install rspec

             Se você quiser mais usabilidade, instale o pacote zentest:

               gem install ZenTest

             Agora instale o pacote autotest-notification. Essa gem configura o autotest (ZenTest) para enviar mensagens
             para softwares como o Growl, LibNotify, and Snarl, mostrando uma janela com os resultados. Leia o arquivo
             README do projeto para saber como instalar: http://github.com/carlosbrando/autotest-notification/. Com
             essas três gems, nossa jornada se torna divertida!


                                                                                                                       9
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir


               Para completar a bagagem, visite a página do Shoes e leia como instalar em seu sistema operacional. Sim,
               Shoes é muito divertido! Nós finalizaremos nossa brincadeira com ele. Acesse http://github.com/shoes/
               shoes/downloads ou http://github.com/shoes/shoes. Para aprender como usar e executar o Shoes leia o
               ebook Nobody knows Shoes disponível em http://github.com/shoes/shoes/downloads.

               Agora vamos começar nossa viagem teste a teste no mundo BDD!


               CRIANDO O ARQUIVO RSPEC

               Primeiro crie a pasta dice e dentro dela crie as pastas lib e spec. Agora crie o arquivo dice_spec.rb dentro da
               pasta spec. Bem! O que está esperando! Vamos escrever o primeiro requisito nesse arquivo. Agora começa
               a diversão!

                 require "rubygems"
                 require "spec"

                 require "lib/dice"

                 describe Dice do
                   it "deve ter números entre 1 e 6"
                 end

               Para executar esse teste abra o terminal, entre na pasta dice, depois digite o comando de teste:

                 cd dice
                 spec spec/dice_spec
                          /

               Em nosso exemplo com autotest, apenas digite o seguinte comando:




10
Capítulo 1: Fazendo a classe Dice usando BDD

  autospec

Agora o teste executa automaticamente toda vez que salvarmos o arquivo. Voltando para nosso exemplo. A
saída do primeiro teste quebra porque precisamos criar a classe Dice no arquivo lib/dice.rb.

  spec --autospec spec/dice_spec.rb
                      /          rb
  ./spec/dice_spec.rb
   /    /          rb:6: uninitialized constant Dice (NameError)



ESCREVA A CLASSE DICE

Para resolver o erro inicial, apenas crie a classe Dice:

  class Dice
  end

A saída mostra o requisito pendente:

  Pending:

  Dice deve ter números entre 1 e 6 (Not Yet Implemented)
  ./spec/dice_spec.rb
   /    /          rb:7

  Finished in 0.04099 seconds

  1 example, 0 failures, 1 pending



OS NÚMEROS NO DADO

O primeiro requisito é delimitar a quantidade de números do dado: 1 a 6:


                                                                                                      11
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir

                 describe Dice do
                     it "deve ter números entre 1 e 6" do
                       dice = Dice new
                              Dice.new
                       (1..6).should include dice.play )
                              should include(      play
                     end
                 end

               Saída:

                 F

                 1)
                 NoMethodError in 'Dice deve ter números entre 1 e 6'
                 undefined method `play' for #<Dice:0xb7b6986c>
                 ./spec/dice_spec.rb:9:

                 Finished in 0.073369 seconds

                 1 example, 1 failure



               CRIANDO O MÉTODO PLAY ARQUIVO DICE.RB

               Para começar a resolver o problema anterior vamos escrever o método play:

                 class Dice
                   def play
                   end
                 end

               Saída: Ainda vai falhar pois o método play no exemplo anterior retorna nulo.




12
Capítulo 1: Fazendo a classe Dice usando BDD

  F

  1)
  'Dice deve ter números entre 1 e 6' FAILED
  expected 1..6 to include nil
  ./spec/dice_spec.rb
   /    /          rb:9:

  Finished in 0.031104 seconds

  1 example, 1 failure



NÚMERO FORA DO CONJUNTO 1-6

Por experimentação vamos colocar um número fora do conjunto 1-6 para ver o que acontece:

  class Dice
      def play
        10
      end
  end

Output: continua falhando, pois está fora do conjunto.

  F

  1)
  'Dice deve ter números entre 1 e 6' FAILED
  expected 1..6 to include 10
  ./spec/dice_spec.rb
   /    /          rb:9:

  Finished in 0.03021 seconds




                                                                                                   13
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir


                 1 example, 1 failure



               NÚMERO DENTRO DO CONJUNTO 1-6

               Agora, vamos colocar um número entre 1-6 e finalmente a classe Dice passa no teste.

                 class Dice
                     def play
                       6
                     end
                 end

               Output:

                 .

                 Finished in 0.027648 seconds

                 1 example, 0 failures



               NÚMEROS ALEATÓRIOS

               Por enquanto está Ok. Agora vamos trabalhar no requisito dos números aleatórios. Eu vou colocar alguns
               outros requisitos que lembrei, mas não muitos. Vou colocar também a letra x no começo da declaração
               'it'para o rspec ignorá-la. Isso é apenas um truque ;).

                 require "rubygems"
                 require "spec"



14
Capítulo 1: Fazendo a classe Dice usando BDD


  require "lib/dice"

  describe Dice do
      it "deve ter números entre 1 e 6" do
        dice = Dice new
               Dice.new
        (1..6).should include dice.play )
               should include(      play
      end

        # Três grupos de 1000 números aleatórios devem ser diferentes um do outro
        it "deve mostrar números de forma aleatória" do
          dice = Dice new
                 Dice.new
          group1 = (1..1_000).collect dice.play }
                              collect{       play
          group2 = (1..1_000).collect dice.play }
                              collect{       play
          group3 = (1..1_000).collect dice.play }
                              collect{       play
          (group1 == group2).should be_false
                             should
          (group1 == group3).should be_false
                             should
          (group2 == group3).should be_false
                             should
        end

        xit "deve armazenar número da última jogada."
        xit "deve jogar o dado no momento que o objeto for inicializado"
  end

Output:

  .F

  1)
  'Dice deve mostrar números de forma aleatória' FAILED
  expected false got true
           false,
  ./spec/dice_spec.rb
   /    /          rb:18:

  Finished in 0.093321 seconds



                                                                                                    15
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir


                 2 examples, 1 failure



               GERANDO NÚMERO ALEATÓRIO E REFATORANDO

               Agora temos quer gerar números aleatórios e também temos que refatorar o primeiro requisito que delimita a
               saída entre os números 1 a 6. Esse requisito deve ser testado com uma variedade de números ao invés de
               somente um como está agora. Para brincar um pouco com Ruby também eu vou modificar o código do
               require para diminuir o número de linhas.

                 class Dice
                     def play
                       rand
                       rand(6)
                     end
                 end


                 %w{ rubygems spec lib/dice }.each
                                              each{|lib| require lib }

                 describe Dice do
                     it "deve ter somente números entre 1 e 6" do
                       dice = Dice new
                              Dice.new
                       group = (1..1_000).collect dice.play }.join
                                          collect{      play   join
                       group.should_not be_nil
                             should_not
                       group.should_not be_empty
                             should_not
                             should_not include('-') # Números negativos não são permitidos
                       group.should_not include
                       group.should_not include
                             should_not include('0')
                       group.should_not include
                             should_not include('7')
                       group.should_not include
                             should_not include('8')
                       group.should_not include
                             should_not include('9')
                     end




16
Capítulo 1: Fazendo a classe Dice usando BDD


        # Três grupos de 1000 números aleatórios devem ser diferentes um do outro
        it "deve mostrar números de forma aleatória" do
          dice = Dice new
                 Dice.new
          group1 = (1..1_000).collect dice.play }
                              collect{       play
          group2 = (1..1_000).collect dice.play }
                              collect{       play
          group3 = (1..1_000).collect dice.play }
                              collect{       play
          (group1 == group2).should be_false
                             should
          (group1 == group3).should be_false
                             should
          (group2 == group3).should be_false
                             should
        end

        xit "deve armazenar número da última jogada."
        xit "deve jogar o dado no momento que o objeto for inicializado"
  end

Output: rand(6) gera também o número zero, portanto o teste falha.

  F.

  1)
  'Dice deve ter somente números entre 1 e 6' FAILED
  expected "4025132222510540002142312555235104432520522022430445143425254
  51533145101530430012510120055232441422435123332040350424441302405340420
  50050324205500223120330524430331015422350203015044053545205524012055023
  10100333140520435320541010244153022003403143022550340451124322335450431
  5335402445045511" not to include "0"
  ./spec/dice_spec.rb
   /    /          rb:10:

  Finished in 0.046589 seconds

  2 examples, 1 failure




                                                                                                     17
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir


               RESOLVENDO A FALHA DO NÚMERO ALEATÓRIO

               Finalmente vamos ajeitar o comando para rand(6) + 1. Dessa forma limita a saída entre 1 e 6. Vamos
               aproveitar para refatorar o primeiro requisito para usar expressões regulares. Agora o teste passa :).

                 class Dice
                     def play
                       rand
                       rand(6) + 1
                     end
                 end


                 %w{ rubygems spec lib/dice }.each {|lib| require lib}
                                              each

                 describe Dice do
                     it "deve ter somente números entre 1 e 6" do
                       dice = Dice new
                              Dice.new
                       group = (1..1_000).collect dice.play }.join
                                          collect{      play   join
                       group.should match
                             should match(/^[1-6]*[1-6]$/)
                     end

                     # Três grupos de 1000 números aleatórios devem ser diferentes um do outro
                     it "deve mostrar números de forma aleatória" do
                       dice = Dice new
                              Dice.new
                       group1 = (1..1_000).collect dice.play }
                                           collect{       play
                       group2 = (1..1_000).collect dice.play }
                                           collect{       play
                       group3 = (1..1_000).collect dice.play }
                                           collect{       play
                       (group1 == group2).should be_false
                                          should
                       (group1 == group3).should be_false
                                          should
                       (group2 == group3).should be_false
                                          should
                     end

                     xit "deve armazenar número da última jogada."




18
Capítulo 1: Fazendo a classe Dice usando BDD

        xit "deve jogar o dado no momento que o objeto for inicializado"
  end



ARMAZENANDO O NÚMERO DO DADO

Vamos trabalhar no próximo requisito: "deve armazenar número da última jogada.". Eu criarei o método
show_number e colocarei uma constante para o teste passar.

  %w{rubygems spec lib/dice}.each {|lib| require lib}
                             each

  describe Dice do

        it "deve ter somente números entre 1 e 6" do
          dice = Dice new
                 Dice.new
          group = (1..1_000).collect dice.play }.join
                             collect{      play   join
          group.should match
                should match(/^[1-6]*[1-6]$/)
        end

        # Três grupos de 1000 números aleatórios devem ser diferentes um do outro
        it "deve mostrar números de forma aleatória" do
          dice = Dice new
                 Dice.new
          group1 = (1..1_000).collect dice.play }
                              collect{       play
          group2 = (1..1_000).collect dice.play }
                              collect{       play
          group3 = (1..1_000).collect dice.play }
                              collect{       play
          (group1 == group2).should be_false
                             should
          (group1 == group3).should be_false
                             should
          (group2 == group3).should be_false
                             should
        end

        it "deve armazenar número da última jogada." do
          dice = Dice new
                 Dice.new
          dice.play
               play



                                                                                                       19
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir

                         dice.show_number to_s.should match
                              show_number.to_s should match(/^[1-6]*[1-6]$/)
                       end

                       xit "deve jogar o dado no momento que o objeto for inicializado"
                 end


                 class Dice
                     def play
                       rand
                       rand(6) + 1
                     end

                       def show_number
                         3
                       end
                 end



               TROCANDO CONSTANTE POR VARIÁVEL

               Essa é uma regra importante no BDD. Agora você pode mudar a constante por uma variável de instância na
               classe dados. O teste continua passando.

                 class Dice
                     def play
                       @number = rand
                                 rand(6) + 1
                     end

                       def show_number
                         @number
                       end
                 end




20
Capítulo 1: Fazendo a classe Dice usando BDD


JOGAR O DADO NA INICIALIZAÇÃO DO OBJETO

Agora eu quero que o dado seja jogado quando ele for inicializado. O próximo teste quebrará.

  %w{rubygems spec lib/dice}.each {|lib| require lib}
                             each

  describe Dice do

      it "deve ter somente números entre 1 e 6" do
        dice = Dice new
               Dice.new
        group = (1..1_000).collect dice.play }.join
                           collect{      play   join
        group.should match
              should match(/^[1-6]*[1-6]$/)
      end

      # Três grupos de 1000 números aleatórios devem ser diferentes um do outro
      it "deve mostrar números de forma aleatória" do
        dice = Dice new
               Dice.new
        group1 = (1..1_000).collect dice.play }
                            collect{       play
        group2 = (1..1_000).collect dice.play }
                            collect{       play
        group3 = (1..1_000).collect dice.play }
                            collect{       play
        (group1 == group2).should be_false
                           should
        (group1 == group3).should be_false
                           should
        (group2 == group3).should be_false
                           should
      end

      it "deve armazenar número da última jogada." do
        dice = Dice new
               Dice.new
        dice.play
             play
        dice.show_number to_s.should match
             show_number.to_s should match(/^[1-6]*[1-6]$/)
      end

      it "deve jogar o dado na inicialização do objeto." do
        Dice new.show_number to_s.should match
        Dice.new show_number.to_s should match(/^[1-6]*[1-6]$/)




                                                                                                      21
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir

                        end

                 end

               Output:

                 ...F

                 1)
                 'Dice deve jogar o dado na inicialização do objeto.' FAILED
                 expected "" to match /^[1-6]*[1-6]$/
                 ./spec/dice_spec.rb
                  /    /          rb:29:

                 Finished in 0.12371 seconds

                 4 examples, 1 failure



               USANDO O MÉTODO INITIALIZE

               Agora eu finalizo a classe Dice colocando o método initialize com uma mensagem para o método play. O
               teste passa.

                 class Dice
                     def initialize
                       play
                     end

                        def play
                          @number = rand
                                    rand(6) + 1
                        end




22
Capítulo 1: Fazendo a classe Dice usando BDD

        def show_number
          @number
        end
  end



VAMOS REFATORAR

Agora eu posso fazer uma pequena refatoração no arquivo dice_spec.rb. Eu colocarei um bloco
before(:each) para simplificar o código. Farei também uma refatoração no terceiro requisito: "deve
armazenar número da última jogada". Agora ele funciona com uma grande quantidade de números. A lógica
é se o último número é armazenado então dois grupos de 100 números são diferentes entre si.

  %w{rubygems spec lib/dice}.each {|lib| require lib}
                             each

  describe Dice do
      before :each do
      before(:each)
        @dice = Dice new
                Dice.new
      end

        it "deve ter somente números entre 1 e 6" do
          group = (1..1_000).collect @dice.play }.join
                             collect{       play   join
          group.should match
                should match(/^[1-6]*[1-6]$/)
        end

        # Três grupos de 1000 números aleatórios devem ser diferentes um do outro
        it "deve mostrar números de forma aleatória" do
          group1 = (1..1_000).collect @dice.play }
                              collect{       play
          group2 = (1..1_000).collect @dice.play }
                              collect{       play
          group3 = (1..1_000).collect @dice.play }
                              collect{       play
          (group1 == group2).should be_false
                             should
          (group1 == group3).should be_false
                             should




                                                                                                    23
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir

                         (group2 == group3).should be_false
                                            should
                       end

                       it "deve armazenar número da última jogada." do
                           group1 = (1..100).collect do
                                             collect
                             @dice.play
                                   play
                             @dice.show_number
                                   show_number
                           end
                           group2 = (1..100).collect do
                                             collect
                             @dice.play
                                   play
                             @dice.show_number
                                   show_number
                           end
                           (group1 == group2).should be_false
                                               should
                       end

                       it "deve jogar o dado na inicialização do objeto." do
                         @dice.show_number to_s.should match
                               show_number.to_s should match(/^[1-6]*[1-6]$/)
                       end

                 end



               BRINCANDO COM A CLASSE DICE

               Agora que a classe foi finalizada vamos brincar com ela no irb!

                 >>   require 'dice'
                 =>   true
                 >>   dice = Dice new
                             Dice.new
                 =>   #<Dice:0xb7a64188 @number=5>
                 >>   dice.show_number
                           show_number
                 =>   5




24
Capítulo 1: Fazendo a classe Dice usando BDD

  >> dice.class
          class
  => Dice

Jogando o dado somente uma vez e deixando ele de lado:

  >> Dice new.show_number
     Dice.new show_number
  => 2

Jogar o dado várias vezes:

  >> 20.times print dice.play }
        times{            play
  21636456135236136236=> 20

Três dados:

  >>   yellowdice = [Dice new, Dice new, Dice new]
                     Dice.new Dice.new Dice.new
  =>   [#<Dice:0xb7a3e3d4 @number=3>, #<Dice:0xb7a3e3ac @number=5>, #<Dice:0xb7a3e384 @number=5>]
  >>   yellowdice.each |dice| puts dice.show_number }
                  each{                  show_number
  3
  5
  5
  =>   [#<Dice:0xb7a3e3d4 @number=3>, #<Dice:0xb7a3e3ac @number=5>, #<Dice:0xb7a3e384 @number=5>]

Jogar novamente o mesmo dado

  >> yellowdice.each |dice| puts dice.play }
                each{                  play
  5
  2
  5
  => [#<Dice:0xb7a3e3d4 @number=5>, #<Dice:0xb7a3e3ac @number=2>, #<Dice:0xb7a3e384 @number=5>]

Qual o maior valor entre os três dados da última jogada?



                                                                                                    25
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir

                 >> puts yellowdice.collect |item| item.show_number }.max
                                    collect{            show_number   max
                 5
                 => nil

               E qual o menor valor?

                 >> puts yellowdice.collect |item| item.show_number }.min
                                    collect{            show_number   min
                 2
                 => nil

               Espere um pouco. No último exemplo eu usei 3 dados?!? Ahaaa! Isso parece com os dados do jogo War.
               Nós criaremos os dados do jogo war no próximo capítulo.




26
Capítulo 2: Reproduzindo os dados do jogo War




Capítulo 2

             Reproduzindo os dados do jogo War


             DESCRIÇÃO DO JOGO WAR

             Finalmente terminei a classe Dice! Mas eu quero algo mais excitante! Eu quero reproduzir em uma classe
             Ruby os dados do jogo War. Isso mesmo! Aqueles 6 dados. 3 vermelhos e 3 amarelos que representam
             ataque e defesa respectivamente.

             Eu usarei dois arrays: reddice e yellowdice para armazenar os valores dos dados. Lembrei agora que o uso
             dos dados depende do número de exércitos do atacante e do defensor. Mas nesse experimento eu pensarei
             somente na manipulação dos dados no jogo. Eles podem ser manuseados com 1, 2 ou 3 dados vermelhos
             contra 1, 2 ou 3 dados amarelos. Eu terei que comparar o maior valor dos dados vermelhos com o maior
             valor entre os dados amarelos e assim sucessivamente com os demais dados (do maior para o menor valor).
             Em caso de empate o amarelo vence. O vermelho só vence quando o número for maior que o amarelo.




                                                                                                                      27
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir


               Bem, eu acho que é só. Vamos agir agora!


               TESTANDO COMPARAÇÃO DE ARRAYS

               Nos primeiros testes que eu fiz em meu computador, tive problemas com comparação de arrays. Paralelo a
               isso me lembrei que é imprescindível o uso de comparação de arrays na classe WarDice. Vamos incluir um
               teste de comparação de arrays no arquivo dice_spec.rb e verificar o comportamento:

                 describe Array do
                     it "deve ser comparável" do
                       ([8,9,10] > [1,2,3]).should be_true
                                            should
                     end
                 end

               Output:

                 ....F

                 1)
                 NoMethodError in 'Array deve ser comparável'
                 undefined method `>' for [8, 9, 10]:Array
                 ./spec/dice_spec.rb:43:

                 Finished in 0.039464 seconds

                 5 examples, 1 failure




28
Capítulo 2: Reproduzindo os dados do jogo War


INCLUINDO O MÓDULO COMPARABLE

Para solucionar o problema anterior, apenas inclua o módulo comparable no arquivo dice.rb. Eu farei isso
usando uma forma simplificada para brincar com as possibilidades do Ruby :).

  class Array; include Comparable; end

Agora o teste passa.


NÚMERO DE DADOS

Agora vou trabalhar no primeiro requisito: permite a utilização de 1, 2 or 3 dados, para o ataque ou
defesa.. Na classe WarDice eu vou colocar de propósito um número diferente de 1, 2, 3 para gerar um erro.

  describe Wardice do
      it "permite a utilização de 1, 2 or 3 dados, para o ataque ou defesa." do
        wardice = Wardice new(0, 3)
                  Wardice.new
        wardice.red to_s.should match
                red.to_s should match(/^[1-3]$/)
        wardice.yellow to_s.should match
                yellow.to_s should match(/^[1-3]$/)
      end

        it "compara os valores do maior para o menor e salva em um array"
  end


  class Wardice
      attr_reader :red :yellow
                   red,

        def initialize red, yellow)
            initialize(
          @red, @yellow = red, yellow




                                                                                                           29
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir

                       end
                 end

               Output:

                 'Wardice permite a utilização de 1, 2 or 3 dados, para o ataque ou defesa.' FAILED
                 expected "0" to match /^[1-3]$/
                 ./spec/dice_spec.rb
                  /    /          rb:50:

                 Finished in 0.032203 seconds

                 8 examples, 1 failure, 2 pending



               RESOLVENDO O PROBLEMA DOS NÚMEROS

               Lógica: Se a classe for inicializada com números diferentes da lista 1-3 então as variáveis serão preenchidas
               com um número aleatório variando de 1 a 3. Eu farei também uma pequena refatoração no arquivo spec
               para que ele fique preparado para a situação em que a quantidade de dados for correta. Você pode ver a
               solução abaixo:

                 class WarDice
                     attr_reader :red :yellow
                                  red,

                       def initialize red, yellow)
                           initialize(
                         @red, @yellow = red, yellow
                         @red = rand
                                rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty?
                                                     to_s.grep           empty?
                         @yellow = rand
                                   rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty?
                                                           to_s.grep            empty?
                       end
                 end

                 describe WarDice do



30
Capítulo 2: Reproduzindo os dados do jogo War

        it "permite a utilização de 1, 2 or 3 dados, para o ataque ou defesa." do
          wardice = Wardice new(0, 7)
                    Wardice.new
          wardice.red to_s.should match
                  red.to_s should match(/^[1-3]$/)
          wardice.yellow to_s.should match
                  yellow.to_s should match(/^[1-3]$/)

          wardice2 = Wardice new(2, 3)
                     Wardice.new
          wardice2.red should == 2
                   red.should
          wardice2.yellow should == 3
                   yellow.should
        end

        it "compara os valores do maior para o menor e salva em um array"
  end



ARRAY EM ORDEM DECRESCENTE

Esse requisito é muito importante, mas só lembrei dele agora: wardice deve fornecer os resultados dos
dados vermelho e amarelo em arrays em ordem decrescente. Você pode ver a solução abaixo:

  describe WarDice do
      it "permite a utilização de 1, 2 or 3 dados, para o ataque ou defesa." do
        wardice = WarDice new(0, 7)
                  WarDice.new
        wardice.red to_s.should match
                red.to_s should match(/^[1-3]$/)
        wardice.yellow to_s.should match
                yellow.to_s should match(/^[1-3]$/)

          wardice2 = WarDice new(2, 3)
                     WarDice.new
          wardice2.red should == 2
                   red.should
          wardice2.yellow should == 3
                   yellow.should
        end

        it "deve fornecer os resultados dos dados vermelho e amarelo em arrays em ordem decrescente" do
          wardice = Wardice new(3, 3)
                    Wardice.new
          wardice.reddice is_a?(Array).should be_true
                  reddice.is_a?        should



                                                                                                        31
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir

                         wardice.yellowdice is_a?(Array).should be_true
                                 yellowdice.is_a?        should

                         wardice.reddice sort{|x, y| y <=> x }.should == wardice.reddice
                                 reddice.sort                  should            reddice
                         wardice.yellowdice sort{|x, y| y <=> x }.should == wardice.yellowdice
                                 yellowdice.sort                  should            yellowdice
                       end

                       it "compara os valores do maior para o menor e salva em um array"

                 end


                 class wardice
                     attr_reader :red :yellow :reddice :yellowdice
                                  red, yellow, reddice,

                       def initialize red, yellow)
                           initialize(
                         @red, @yellow = red, yellow
                         @red = rand
                                rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty?
                                                     to_s.grep           empty?
                         @yellow = rand
                                   rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty?
                                                           to_s.grep            empty?

                         @reddice = []
                         @yellowdice = []

                         @dice = Dice new
                                 Dice.new
                         @red.times
                              times{|row| @reddice[row] = [@dice.play }
                                                                 play]
                         @yellow.times |row| @yellowdice[row] = [@dice.play }
                                 times{                                 play]
                       end
                 end

               Output:

                 'wardice deve fornecer os resultados dos dados vermelho e amarelo em arrays em ordem decrescente'   FAILE
                 expected: [[5], [2], [4]],
                      got: [[5], [4], [2]] (using ==
                                                  ==)
                 ./spec/dice_spec.rb
                  /    /          rb:63:



32
Capítulo 2: Reproduzindo os dados do jogo War


  Finished in 0.035218 seconds

  9 examples, 1 failure, 2 pending



SOLUCIONANDO O PROBLEMA DO ARRAY EM ORDEM DECRESCENTE
  class WarDice
      attr_reader :red :yellow :reddice :yellowdice
                   red, yellow, reddice,

        def initialize red, yellow)
            initialize(
          @red, @yellow = red, yellow
          @red = rand
                 rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty?
                                      to_s.grep           empty?
          @yellow = rand
                    rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty?
                                            to_s.grep            empty?

          @reddice = []
          @yellowdice = []

          @dice = Dice new
                  Dice.new
          @red.times
               times{|row| @reddice[row] = [@dice.play }
                                                  play]
          @yellow.times |row| @yellowdice[row] = [@dice.play }
                  times{                                 play]

          @reddice.sort!
                   sort!{|x,y| y <=> x }
          @yellowdice.sort!
                      sort!{|x,y| y <=> x }
        end
  end

Agora o teste passa.




                                                                                                     33
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir


               COMPARANDO OS VALORES

               Vamos trabalhar no último requisito: compara os valores do maior para o menor e salva em um array.

                 describe Wardice do
                     it "permite a utilização de 1, 2 or 3 dados, para o ataque ou defesa." do
                       wardice = Wardice new(0, 7)
                                 Wardice.new
                       wardice.red to_s.should match
                               red.to_s should match(/^[1-3]$/)
                       wardice.yellow to_s.should match
                               yellow.to_s should match(/^[1-3]$/)

                       wardice2 = Wardice new(2, 3)
                                  Wardice.new
                       wardice2.red should == 2
                                red.should
                       wardice2.yellow should == 3
                                yellow.should
                     end

                     it "deve fornecer os resultados dos dados vermelho e amarelo em arrays em ordem decrescente" do
                       wardice = Wardice new(3, 3)
                                 Wardice.new
                       wardice.reddice is_a?(Array).should be_true
                               reddice.is_a?        should
                       wardice.yellowdice is_a?(Array).should be_true
                               yellowdice.is_a?        should

                       wardice.reddice sort{|x, y| y <=> x }.should == wardice.reddice
                               reddice.sort                  should            reddice
                       wardice.yellowdice sort{|x, y| y <=> x }.should == wardice.yellowdice
                               yellowdice.sort                  should            yellowdice

                     end

                     it "compara os valores do maior para o menor e salva em um array" do
                       wardice = Wardice new(3, 2)
                                 Wardice.new
                       wardice.reddice first.should > wardice.reddice last
                               reddice.first should           reddice.last
                       wardice.attack
                               attack

                       wardice.result
                               result[0].should == "Red Win" if wardice.reddice
                                         should                         reddice[0] > wardice.yellowdice
                                                                                             yellowdice[0]
                       wardice.result
                               result[0].should == "Yellow Win" if wardice.reddice
                                         should                            reddice[0] <= wardice.yellowdice
                                                                                                 yellowdice[0]




34
Capítulo 2: Reproduzindo os dados do jogo War

        end
  end

A classe WarDice com os testes passando por completo:

  class Wardice
      attr_reader :red :yellow :reddice :yellowdice :result
                   red, yellow, reddice, yellowdice,

        def initialize red, yellow)
            initialize(
          @red, @yellow = red, yellow
          @red = rand
                 rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty?
                                      to_s.grep           empty?
          @yellow = rand
                    rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty?
                                            to_s.grep            empty?

          @reddice = []
          @yellowdice = []
          @result = []

          @dice = Dice new
                  Dice.new
          @red.times
               times{|row| @reddice[row] = [@dice.play }
                                                  play]
          @yellow.times |row| @yellowdice[row] = [@dice.play }
                  times{                                 play]

          @reddice.sort!
                   sort!{|x, y| y <=> x }
          @yellowdice.sort!
                      sort!{|x, y| y <=> x }
        end

        def attack
          @reddice.each_with_index do |item, index|
                   each_with_index
            next if @yellowdice[index].nil?
                                       nil?
            reddice = item
            yellowdice = @yellowdice[index]

              if reddice > yellowdice
                @result << "Vermelho Venceu!"
              else



                                                                                                     35
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir

                             @result << "Amarelo Venceu!"
                           end
                         end
                       end
                 end



               BRINCANDO COM A CLASSE WARDICE

               Abra o irb e digite a sequência abaixo:

                 >> require 'dice'
                 => true

               Inicialize a classe WarDice. O primeiro parâmetro é o número de dados vermelhos e o segundo é o número
               de dados amarelos:

                 >> wardice = WarDice new(2, 3)
                              WarDice.new
                 => #<WarDice:0xb7b0b410 @yellowdice=[[6], [1], [1]], @reddice=[[3], [1]], @dice=#<Dice:0xb7b0ae0c
                 @number=6>, yellow3, result["Yellow Win", "Yellow Win"], red2
                        = >

               Mostra o números nos dados amarelos e vermelhos:

                 >>   puts wardice.reddice
                                   reddice
                 3
                 1
                 =>   nil
                 >>   puts wardice.yellowdice
                                   yellowdice
                 6
                 1
                 1
                 =>   nil



36
Capítulo 2: Reproduzindo os dados do jogo War


Mostra o resultado:

  >> puts wardice.result
                  result
  Yellow Win
  Yellow Win
  => nil

A saída completa em um único comando:

  >> war.reddice each_with_index{ |item, index| puts "Red:#{item} Yellow:#{war.yellowdice
         reddice.each_with_index                                               yellowdice[index]}
  - #{war.result
          result[index]}"}
  Red:3 Yellow:6 - Yellow Win
  Red:1 Yellow:1 - Yellow Win
  => [[3], [1]]

Agora já temos as ferramentas para brincar. Então no próximo capítulo nós usaremos essas classes para
fazer uma bela aplicação gráfica usando Shoes.




                                                                                                        37
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir




Capítulo 3

               Jogando dados com Shoes


               UM PEQUENO TESTE COM A CLASSE DICE E SHOES

               Nesse capítulo vamos criar uma interface gráfica usando Shoes e a classe WarDice, mas primeiro vamos
               fazer um simples teste com a classe Dice. Você deve criar o arquivo diceshoes.rb, então cole o código
               abaixo dentro dele e salve dentro do mesmo diretório do arquivo dice.rb. Finalmente, execute ele com o
               Shoes para ver o resultado.

               Observe que eu apenas inclui o arquivo dice.rb com um require no começo do código abaixo:

                 require 'dice'
                 Shoes app :title => "Teste com a classe Dice", :width => 500, :height => 500 do
                 Shoes.app
                     background aliceblue

                     para "Bem Vindo! Esse é um exemplo de uso da classe Dice.", :weight => "bold"




38
Capítulo 3: Jogando dados com Shoes


         dice = Dice new
                Dice.new

         # Imprime na tela os números dos dados jogados com cores aleatórias
         1_000.times do
               times
           r, g, b = rand, rand, rand
           para dice.play :stroke => rgb **3, g**
                     play,            rgb(r**    **3, b**
                                                       **3), :size => "large"
         end
  end

Saída:




                                                                                                    39
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir


               O CÓDIGO SHOES DO APLICATIVO QUE USA A CLASSE WARDICE

               Finalmente a última aplicação. copie o código seguinte em um novo arquivo e salve com o nome
               wardiceshoes.rb na pasta lib. Eu fiz alguns comentários através do código para facilitar a compreensão.
               Faça um bom experimento.

                 require 'dice'

                 Shoes app :title => "Dados do Jogo War", :width => 500, :height => 500 do
                 Shoes.app
                     background gradient black, teal )
                                gradient(

                     # Listbox com a quantidade de dados vermelhos: 1, 2 or 3
                     para "Red", :stroke => tomato
                     @numberreddice = list_box :items => ["1", "2", "3"],
                       :width => 70, :choose => "3" do |list|
                     end

                     para " X ", :stroke => snow

                     # Listbox com a quantidade de dados amarelos: 1, 2 or 3
                     @numberyellowdice = list_box :items => ["1", "2", "3"],
                       :width => 70, :choose => "3" do |list|
                     end
                     para "Yellow", :stroke => yellow

                     # Define uma posição aleatória
                     @a = @b = @c = []

                      (40..200).step
                                step(10){ |x| @a << x }
                     (230..450).step
                                step(10){ |y| @b << y }
                     (80..450).step
                               step(10){ |z| @c << z }
                                            |

                     # Variáveis que vão armazenar os valores do objeto wardice.



40
Capítulo 3: Jogando dados com Shoes

@reddice = @yellowdice = @resulttext = []

button "Attack", :width => 80 do

  # Limpa a tela
  @dice.each |d| d.remove }
        each{       remove
  @resulttext.each |a| a.remove }
              each{        remove

  # O objeto wardice is inicializado
  wardice = WarDice new( @numberreddice.text to_i, @numberyellowdice.text to_i )
            WarDice.new                 text.to_i                    text.to_i
  @reddice    = wardice.reddice
                        reddice
  @yellowdice = wardice.yellowdice
                        yellowdice
  @result     = wardice.result
                        result

  # Cada dado é desenhado em uma posição aleatória
  @reddice.each |item| draw @a[rand
           each{        draw(    rand(@a.length
                                         length)], @c[rand
                                                      rand(@c.length
                                                              length)], item.to_s to_i, 1, true ) }
                                                                             to_s.to_i
  @yellowdice.each |item| draw @b[rand
              each{        draw(    rand(@b.length
                                            length)], @c[rand
                                                         rand(@c.length
                                                                 length)], item.to_s to_i, 2, true )}
                                                                                to_s.to_i

end

button "Verify", :width => 80 do

  # Limpa a tela
  @dice.each |d| d.remove }
        each{       remove
  @resulttext.each |a| a.remove }
              each{        remove

  # posição inicial dos dados
  leftyellow = 250
  leftred    = 150
  topred     = topyellow = 100

  # Cada dado é desenhado em uma posição definida
  @reddice.each do |item|
           each
    draw leftred, topred, item.to_s to_i, 1, false )
    draw(                       to_s.to_i




                                                                                            41
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir

                         topred += 100
                       end

                       @yellowdice.each do |item|
                                   each
                         draw leftyellow, topyellow, item.to_s to_i, 2, false )
                         draw(                            to_s.to_i
                         topyellow += 100
                       end

                       # Posição inicial para a lista com o resultado
                       leftresult = 300
                       topresult = 80

                       # Os resultados são impressos na tela em uma posição definida
                       @result.each_with_index do |item, index|
                               each_with_index
                         @resulttext[index] = para item.to_s :stroke => snow, :top => topresult, :left => leftresult
                                                        to_s,
                         topresult += 100
                       end

                     end


                     # O método draw foi baseado no projeto Pretty Dice, escrito por Ed Heil
                     @dice = []

                     def draw left, top, number, color, rotate )
                         draw(

                           imagewidth = 60
                           imageheight = 60

                           i = image imagewidth, imageheight,
                               image(
                               :top => top - imagewidth / 2,
                               :left => left - imagewidth / 2,
                               :shadow => 10, :center => true ) do




42
Capítulo 3: Jogando dados com Shoes

if color == 1
  strokecolor = red
  fillrectanglecolor = tomato
  filldotscolor = darkred
else
  strokecolor = yellow
  fillrectanglecolor = lightgoldenrodyellow
  filldotscolor = chocolate
end

sw = 1
strokewidth sw
stroke strokecolor

fill fillrectanglecolor

inset = 2
inset2 = 8

rect inset, inset, imagewidth-inset-sw, imageheight-inset-sw, 10 )
rect(                        -     -               -     -

fill filldotscolor

ovalradius = 10
low = inset2
high = imagewidth - inset2 - ovalradius
mid = ( imagewidth - ovalradius ) / 2

oval mid, mid, ovalradius ) if number % 2 == 1
oval(

if number > 1
  oval low, low, ovalradius )
  oval(
  oval high, high, ovalradius )
  oval(
end




                                                                                   43
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir


                                 if number > 3
                                   oval low, high, ovalradius )
                                   oval(
                                   oval high, low, ovalradius )
                                   oval(
                                 end

                                 if number > 5
                                   oval mid, low, ovalradius )
                                   oval(
                                   oval mid, high, ovalradius )
                                   oval(
                                 end

                             end # fim do bloco `image`

                             i.rotate rand 359 ) ) if rotate
                               rotate( rand(

                             @dice << i

                       end

                 end



               BRINCANDO COM O APLICATIVO

               Abaixo você pode ver o aplicativo em ação. Você deve escolher o número de dados vermelhos e amarelos
               no respectivo listbox. Depois clique no botão ataque para jogar os dados. Agora é só se divertir!




44
Capítulo 3: Jogando dados com Shoes




Agora clique no botão verificar para saber quem venceu!




                                                                                          45
Aprenda BDD Jogando Dados! - Seu comportamento é se divertir




46

Mais conteúdo relacionado

Semelhante a Aprenda bdd-jogando-dados-ebook

Dojo UECE - javaCE
Dojo UECE - javaCEDojo UECE - javaCE
Dojo UECE - javaCEYuri Adams
 
Astro Pi - Explorando o Sense Hat
Astro Pi - Explorando o Sense HatAstro Pi - Explorando o Sense Hat
Astro Pi - Explorando o Sense HatAna Carneirinho
 
Coding Dojo .Net Architects - 30.01.2010
Coding Dojo .Net Architects - 30.01.2010Coding Dojo .Net Architects - 30.01.2010
Coding Dojo .Net Architects - 30.01.2010Vinicius Quaiato
 
Mobile Game Case: Bboy in Heaven´s Mission
Mobile Game Case: Bboy in Heaven´s MissionMobile Game Case: Bboy in Heaven´s Mission
Mobile Game Case: Bboy in Heaven´s Missionelliando dias
 

Semelhante a Aprenda bdd-jogando-dados-ebook (6)

Dojo UECE - javaCE
Dojo UECE - javaCEDojo UECE - javaCE
Dojo UECE - javaCE
 
Astro Pi - Explorando o Sense Hat
Astro Pi - Explorando o Sense HatAstro Pi - Explorando o Sense Hat
Astro Pi - Explorando o Sense Hat
 
Object Oriented Programming
Object Oriented ProgrammingObject Oriented Programming
Object Oriented Programming
 
Coding Dojo .Net Architects - 30.01.2010
Coding Dojo .Net Architects - 30.01.2010Coding Dojo .Net Architects - 30.01.2010
Coding Dojo .Net Architects - 30.01.2010
 
Multimeios em educação
Multimeios em educaçãoMultimeios em educação
Multimeios em educação
 
Mobile Game Case: Bboy in Heaven´s Mission
Mobile Game Case: Bboy in Heaven´s MissionMobile Game Case: Bboy in Heaven´s Mission
Mobile Game Case: Bboy in Heaven´s Mission
 

Último

Depende De Nós! José Ernesto Ferraresso.ppsx
Depende De Nós! José Ernesto Ferraresso.ppsxDepende De Nós! José Ernesto Ferraresso.ppsx
Depende De Nós! José Ernesto Ferraresso.ppsxLuzia Gabriele
 
Caça palavras - BULLYING
Caça palavras  -  BULLYING  Caça palavras  -  BULLYING
Caça palavras - BULLYING Mary Alvarenga
 
Aula 5 - A Guerra acabou, o mundo se modificou..pptx
Aula 5 - A Guerra acabou, o mundo se modificou..pptxAula 5 - A Guerra acabou, o mundo se modificou..pptx
Aula 5 - A Guerra acabou, o mundo se modificou..pptxMarceloDosSantosSoar3
 
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdf
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdfARTE BARROCA E ROCOCO BRASILEIRO-min.pdf
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdfItaloAtsoc
 
Peixeiras da Coruña. O Muro da Coruña. IES Monelos
Peixeiras da Coruña. O Muro da Coruña. IES MonelosPeixeiras da Coruña. O Muro da Coruña. IES Monelos
Peixeiras da Coruña. O Muro da Coruña. IES MonelosAgrela Elvixeo
 
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)profesfrancleite
 
arte retrato de um povo - Expressão Cultural e Identidade Nacional
arte retrato de um povo - Expressão Cultural e Identidade Nacionalarte retrato de um povo - Expressão Cultural e Identidade Nacional
arte retrato de um povo - Expressão Cultural e Identidade Nacionalidicacia
 
Treinamento de Avaliação de Desempenho HBB
Treinamento de Avaliação de Desempenho HBBTreinamento de Avaliação de Desempenho HBB
Treinamento de Avaliação de Desempenho HBBDiegoFelicioTexeira
 
autismo conhecer.pptx, Conhecer para entender
autismo conhecer.pptx, Conhecer para entenderautismo conhecer.pptx, Conhecer para entender
autismo conhecer.pptx, Conhecer para entenderLucliaResende1
 
Trabalho DAC História 25 de Abril de 1974
Trabalho DAC História 25 de Abril de 1974Trabalho DAC História 25 de Abril de 1974
Trabalho DAC História 25 de Abril de 1974AnaRitaFreitas7
 
Aula 6 - O Imperialismo e seu discurso civilizatório.pptx
Aula 6 - O Imperialismo e seu discurso civilizatório.pptxAula 6 - O Imperialismo e seu discurso civilizatório.pptx
Aula 6 - O Imperialismo e seu discurso civilizatório.pptxMarceloDosSantosSoar3
 
Poder do convencimento,........... .
Poder do convencimento,...........         .Poder do convencimento,...........         .
Poder do convencimento,........... .WAGNERJESUSDACUNHA
 
Cruzadinha da dengue - Mosquito Aedes aegypti
Cruzadinha da dengue - Mosquito Aedes aegyptiCruzadinha da dengue - Mosquito Aedes aegypti
Cruzadinha da dengue - Mosquito Aedes aegyptiMary Alvarenga
 
Atividade de matemática para simulado de 2024
Atividade de matemática para simulado de 2024Atividade de matemática para simulado de 2024
Atividade de matemática para simulado de 2024gilmaraoliveira0612
 
Apresentação sobrea dengue educação.pptx
Apresentação sobrea dengue educação.pptxApresentação sobrea dengue educação.pptx
Apresentação sobrea dengue educação.pptxtaloAugusto8
 
Como fazer um Feedback Eficaz - Comitê de Gestores
Como fazer um Feedback Eficaz - Comitê de GestoresComo fazer um Feedback Eficaz - Comitê de Gestores
Como fazer um Feedback Eficaz - Comitê de GestoresEu Prefiro o Paraíso.
 

Último (20)

Abordagem 2. Análise temática (Severino, 2013)_PdfToPowerPoint.pdf
Abordagem 2. Análise temática (Severino, 2013)_PdfToPowerPoint.pdfAbordagem 2. Análise temática (Severino, 2013)_PdfToPowerPoint.pdf
Abordagem 2. Análise temática (Severino, 2013)_PdfToPowerPoint.pdf
 
Depende De Nós! José Ernesto Ferraresso.ppsx
Depende De Nós! José Ernesto Ferraresso.ppsxDepende De Nós! José Ernesto Ferraresso.ppsx
Depende De Nós! José Ernesto Ferraresso.ppsx
 
Caça palavras - BULLYING
Caça palavras  -  BULLYING  Caça palavras  -  BULLYING
Caça palavras - BULLYING
 
Aula 5 - A Guerra acabou, o mundo se modificou..pptx
Aula 5 - A Guerra acabou, o mundo se modificou..pptxAula 5 - A Guerra acabou, o mundo se modificou..pptx
Aula 5 - A Guerra acabou, o mundo se modificou..pptx
 
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdf
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdfARTE BARROCA E ROCOCO BRASILEIRO-min.pdf
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdf
 
Peixeiras da Coruña. O Muro da Coruña. IES Monelos
Peixeiras da Coruña. O Muro da Coruña. IES MonelosPeixeiras da Coruña. O Muro da Coruña. IES Monelos
Peixeiras da Coruña. O Muro da Coruña. IES Monelos
 
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)
 
arte retrato de um povo - Expressão Cultural e Identidade Nacional
arte retrato de um povo - Expressão Cultural e Identidade Nacionalarte retrato de um povo - Expressão Cultural e Identidade Nacional
arte retrato de um povo - Expressão Cultural e Identidade Nacional
 
Treinamento de Avaliação de Desempenho HBB
Treinamento de Avaliação de Desempenho HBBTreinamento de Avaliação de Desempenho HBB
Treinamento de Avaliação de Desempenho HBB
 
Abordagem 1. Análise textual (Severino, 2013).pdf
Abordagem 1. Análise textual (Severino, 2013).pdfAbordagem 1. Análise textual (Severino, 2013).pdf
Abordagem 1. Análise textual (Severino, 2013).pdf
 
autismo conhecer.pptx, Conhecer para entender
autismo conhecer.pptx, Conhecer para entenderautismo conhecer.pptx, Conhecer para entender
autismo conhecer.pptx, Conhecer para entender
 
Trabalho DAC História 25 de Abril de 1974
Trabalho DAC História 25 de Abril de 1974Trabalho DAC História 25 de Abril de 1974
Trabalho DAC História 25 de Abril de 1974
 
Abordagens 4 (Problematização) e 5 (Síntese pessoal) do texto de Severino (20...
Abordagens 4 (Problematização) e 5 (Síntese pessoal) do texto de Severino (20...Abordagens 4 (Problematização) e 5 (Síntese pessoal) do texto de Severino (20...
Abordagens 4 (Problematização) e 5 (Síntese pessoal) do texto de Severino (20...
 
Aula 6 - O Imperialismo e seu discurso civilizatório.pptx
Aula 6 - O Imperialismo e seu discurso civilizatório.pptxAula 6 - O Imperialismo e seu discurso civilizatório.pptx
Aula 6 - O Imperialismo e seu discurso civilizatório.pptx
 
Poder do convencimento,........... .
Poder do convencimento,...........         .Poder do convencimento,...........         .
Poder do convencimento,........... .
 
Cruzadinha da dengue - Mosquito Aedes aegypti
Cruzadinha da dengue - Mosquito Aedes aegyptiCruzadinha da dengue - Mosquito Aedes aegypti
Cruzadinha da dengue - Mosquito Aedes aegypti
 
Atividade de matemática para simulado de 2024
Atividade de matemática para simulado de 2024Atividade de matemática para simulado de 2024
Atividade de matemática para simulado de 2024
 
Apresentação sobrea dengue educação.pptx
Apresentação sobrea dengue educação.pptxApresentação sobrea dengue educação.pptx
Apresentação sobrea dengue educação.pptx
 
Como fazer um Feedback Eficaz - Comitê de Gestores
Como fazer um Feedback Eficaz - Comitê de GestoresComo fazer um Feedback Eficaz - Comitê de Gestores
Como fazer um Feedback Eficaz - Comitê de Gestores
 
Abordagem 3. Análise interpretativa (Severino, 2013)_PdfToPowerPoint.pdf
Abordagem 3. Análise interpretativa (Severino, 2013)_PdfToPowerPoint.pdfAbordagem 3. Análise interpretativa (Severino, 2013)_PdfToPowerPoint.pdf
Abordagem 3. Análise interpretativa (Severino, 2013)_PdfToPowerPoint.pdf
 

Aprenda bdd-jogando-dados-ebook

  • 3. Aprenda BDD Jogando Dados! SEU COMPORTAMENTO É SE DIVERTIR Primeira Edição
  • 5. Aprenda BDD Jogando Dados! SEU COMPORTAMENTO É SE DIVERTIR Primeira Edição por Valério Farias de Carvalho
  • 6. Por Valério Farias de Carvalho. Disponibilizado como Creative Commons Atribuição 2.5 Primeira edição: Julho de 2010 Valério Farias http://www.valeriofarias.com Twitter: @valeriofarias Origem da imagem da capa: http://www.flickr.com/photos/missturner/
  • 7. Aprenda BDD Jogando Dados! INTRODUÇÃO Olá entusiasta do Ruby! Olá entusiasta de BDD! Bem vindo a essa jornada linha a linha, teste por teste, utilizando a técnica do Desenvolvimento Orientado a Comportamento (Behavior Driven Development) em um projeto muito interessante: Simulação dos dados do jogo War!. Eu escrevi esse pequeno livro para aprender BDD e RSpec, por isso eu tinha que falar sobre algo simples e de preferência que fosse divertido. Então eu pensei: Por que não jogar dados! Porque não jogar dados do jogo War! Então aqui está: Aprenda BDD jogando dados! A aplicação que nós criaremos juntos usa duas classes: Dice e WarDice. O primeiro capítulo eu começo construindo o arquivo RSpec da classe Dice e a classe Dice simultaneamente e passo a passo até todos os testes tornarem-se verdes. No segundo capítulo eu continuo o desenvolvimento com a classe WarDice, aquela que fará a simulação de cada dado do jogo war! Finalmente, no terceiro capítulo eu uso as classes criadas em uma divertida aplicação feita em shoes. A filosofia desse livro é aprender fazendo coisas divertidas. Em uma palavra: Experimentação. Então eu espero que você aproveite esse livro simples mas também muito instrutivo. Os testes usados nesse livro não são uma solução definitiva. Eles são somente possibilidades no meio de outras. Como eu disse, eu o escrevi para aprender RSpec. Você pode enviar sugestões, clonar o projeto, modificá-lo e codificá-lo de outra forma. Quem sabe não faremos juntos a versão 2.0 desse livro :). 7
  • 8. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir O código fonte completo da aplicação você pode encontrar no seguinte endereço: https://github.com/ valeriofarias/shoes-war-dice/tree Agora, apenas leia, codifique, teste, compartilhe e se divirta! 8
  • 9. Capítulo 1: Fazendo a classe Dice usando BDD Capítulo 1 Fazendo a classe Dice usando BDD INICIANDO Antes de começarmos a programar vamos instalar os pacotes necessários. Primeiro instale o rspec: gem install rspec Se você quiser mais usabilidade, instale o pacote zentest: gem install ZenTest Agora instale o pacote autotest-notification. Essa gem configura o autotest (ZenTest) para enviar mensagens para softwares como o Growl, LibNotify, and Snarl, mostrando uma janela com os resultados. Leia o arquivo README do projeto para saber como instalar: http://github.com/carlosbrando/autotest-notification/. Com essas três gems, nossa jornada se torna divertida! 9
  • 10. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir Para completar a bagagem, visite a página do Shoes e leia como instalar em seu sistema operacional. Sim, Shoes é muito divertido! Nós finalizaremos nossa brincadeira com ele. Acesse http://github.com/shoes/ shoes/downloads ou http://github.com/shoes/shoes. Para aprender como usar e executar o Shoes leia o ebook Nobody knows Shoes disponível em http://github.com/shoes/shoes/downloads. Agora vamos começar nossa viagem teste a teste no mundo BDD! CRIANDO O ARQUIVO RSPEC Primeiro crie a pasta dice e dentro dela crie as pastas lib e spec. Agora crie o arquivo dice_spec.rb dentro da pasta spec. Bem! O que está esperando! Vamos escrever o primeiro requisito nesse arquivo. Agora começa a diversão! require "rubygems" require "spec" require "lib/dice" describe Dice do it "deve ter números entre 1 e 6" end Para executar esse teste abra o terminal, entre na pasta dice, depois digite o comando de teste: cd dice spec spec/dice_spec / Em nosso exemplo com autotest, apenas digite o seguinte comando: 10
  • 11. Capítulo 1: Fazendo a classe Dice usando BDD autospec Agora o teste executa automaticamente toda vez que salvarmos o arquivo. Voltando para nosso exemplo. A saída do primeiro teste quebra porque precisamos criar a classe Dice no arquivo lib/dice.rb. spec --autospec spec/dice_spec.rb / rb ./spec/dice_spec.rb / / rb:6: uninitialized constant Dice (NameError) ESCREVA A CLASSE DICE Para resolver o erro inicial, apenas crie a classe Dice: class Dice end A saída mostra o requisito pendente: Pending: Dice deve ter números entre 1 e 6 (Not Yet Implemented) ./spec/dice_spec.rb / / rb:7 Finished in 0.04099 seconds 1 example, 0 failures, 1 pending OS NÚMEROS NO DADO O primeiro requisito é delimitar a quantidade de números do dado: 1 a 6: 11
  • 12. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir describe Dice do it "deve ter números entre 1 e 6" do dice = Dice new Dice.new (1..6).should include dice.play ) should include( play end end Saída: F 1) NoMethodError in 'Dice deve ter números entre 1 e 6' undefined method `play' for #<Dice:0xb7b6986c> ./spec/dice_spec.rb:9: Finished in 0.073369 seconds 1 example, 1 failure CRIANDO O MÉTODO PLAY ARQUIVO DICE.RB Para começar a resolver o problema anterior vamos escrever o método play: class Dice def play end end Saída: Ainda vai falhar pois o método play no exemplo anterior retorna nulo. 12
  • 13. Capítulo 1: Fazendo a classe Dice usando BDD F 1) 'Dice deve ter números entre 1 e 6' FAILED expected 1..6 to include nil ./spec/dice_spec.rb / / rb:9: Finished in 0.031104 seconds 1 example, 1 failure NÚMERO FORA DO CONJUNTO 1-6 Por experimentação vamos colocar um número fora do conjunto 1-6 para ver o que acontece: class Dice def play 10 end end Output: continua falhando, pois está fora do conjunto. F 1) 'Dice deve ter números entre 1 e 6' FAILED expected 1..6 to include 10 ./spec/dice_spec.rb / / rb:9: Finished in 0.03021 seconds 13
  • 14. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir 1 example, 1 failure NÚMERO DENTRO DO CONJUNTO 1-6 Agora, vamos colocar um número entre 1-6 e finalmente a classe Dice passa no teste. class Dice def play 6 end end Output: . Finished in 0.027648 seconds 1 example, 0 failures NÚMEROS ALEATÓRIOS Por enquanto está Ok. Agora vamos trabalhar no requisito dos números aleatórios. Eu vou colocar alguns outros requisitos que lembrei, mas não muitos. Vou colocar também a letra x no começo da declaração 'it'para o rspec ignorá-la. Isso é apenas um truque ;). require "rubygems" require "spec" 14
  • 15. Capítulo 1: Fazendo a classe Dice usando BDD require "lib/dice" describe Dice do it "deve ter números entre 1 e 6" do dice = Dice new Dice.new (1..6).should include dice.play ) should include( play end # Três grupos de 1000 números aleatórios devem ser diferentes um do outro it "deve mostrar números de forma aleatória" do dice = Dice new Dice.new group1 = (1..1_000).collect dice.play } collect{ play group2 = (1..1_000).collect dice.play } collect{ play group3 = (1..1_000).collect dice.play } collect{ play (group1 == group2).should be_false should (group1 == group3).should be_false should (group2 == group3).should be_false should end xit "deve armazenar número da última jogada." xit "deve jogar o dado no momento que o objeto for inicializado" end Output: .F 1) 'Dice deve mostrar números de forma aleatória' FAILED expected false got true false, ./spec/dice_spec.rb / / rb:18: Finished in 0.093321 seconds 15
  • 16. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir 2 examples, 1 failure GERANDO NÚMERO ALEATÓRIO E REFATORANDO Agora temos quer gerar números aleatórios e também temos que refatorar o primeiro requisito que delimita a saída entre os números 1 a 6. Esse requisito deve ser testado com uma variedade de números ao invés de somente um como está agora. Para brincar um pouco com Ruby também eu vou modificar o código do require para diminuir o número de linhas. class Dice def play rand rand(6) end end %w{ rubygems spec lib/dice }.each each{|lib| require lib } describe Dice do it "deve ter somente números entre 1 e 6" do dice = Dice new Dice.new group = (1..1_000).collect dice.play }.join collect{ play join group.should_not be_nil should_not group.should_not be_empty should_not should_not include('-') # Números negativos não são permitidos group.should_not include group.should_not include should_not include('0') group.should_not include should_not include('7') group.should_not include should_not include('8') group.should_not include should_not include('9') end 16
  • 17. Capítulo 1: Fazendo a classe Dice usando BDD # Três grupos de 1000 números aleatórios devem ser diferentes um do outro it "deve mostrar números de forma aleatória" do dice = Dice new Dice.new group1 = (1..1_000).collect dice.play } collect{ play group2 = (1..1_000).collect dice.play } collect{ play group3 = (1..1_000).collect dice.play } collect{ play (group1 == group2).should be_false should (group1 == group3).should be_false should (group2 == group3).should be_false should end xit "deve armazenar número da última jogada." xit "deve jogar o dado no momento que o objeto for inicializado" end Output: rand(6) gera também o número zero, portanto o teste falha. F. 1) 'Dice deve ter somente números entre 1 e 6' FAILED expected "4025132222510540002142312555235104432520522022430445143425254 51533145101530430012510120055232441422435123332040350424441302405340420 50050324205500223120330524430331015422350203015044053545205524012055023 10100333140520435320541010244153022003403143022550340451124322335450431 5335402445045511" not to include "0" ./spec/dice_spec.rb / / rb:10: Finished in 0.046589 seconds 2 examples, 1 failure 17
  • 18. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir RESOLVENDO A FALHA DO NÚMERO ALEATÓRIO Finalmente vamos ajeitar o comando para rand(6) + 1. Dessa forma limita a saída entre 1 e 6. Vamos aproveitar para refatorar o primeiro requisito para usar expressões regulares. Agora o teste passa :). class Dice def play rand rand(6) + 1 end end %w{ rubygems spec lib/dice }.each {|lib| require lib} each describe Dice do it "deve ter somente números entre 1 e 6" do dice = Dice new Dice.new group = (1..1_000).collect dice.play }.join collect{ play join group.should match should match(/^[1-6]*[1-6]$/) end # Três grupos de 1000 números aleatórios devem ser diferentes um do outro it "deve mostrar números de forma aleatória" do dice = Dice new Dice.new group1 = (1..1_000).collect dice.play } collect{ play group2 = (1..1_000).collect dice.play } collect{ play group3 = (1..1_000).collect dice.play } collect{ play (group1 == group2).should be_false should (group1 == group3).should be_false should (group2 == group3).should be_false should end xit "deve armazenar número da última jogada." 18
  • 19. Capítulo 1: Fazendo a classe Dice usando BDD xit "deve jogar o dado no momento que o objeto for inicializado" end ARMAZENANDO O NÚMERO DO DADO Vamos trabalhar no próximo requisito: "deve armazenar número da última jogada.". Eu criarei o método show_number e colocarei uma constante para o teste passar. %w{rubygems spec lib/dice}.each {|lib| require lib} each describe Dice do it "deve ter somente números entre 1 e 6" do dice = Dice new Dice.new group = (1..1_000).collect dice.play }.join collect{ play join group.should match should match(/^[1-6]*[1-6]$/) end # Três grupos de 1000 números aleatórios devem ser diferentes um do outro it "deve mostrar números de forma aleatória" do dice = Dice new Dice.new group1 = (1..1_000).collect dice.play } collect{ play group2 = (1..1_000).collect dice.play } collect{ play group3 = (1..1_000).collect dice.play } collect{ play (group1 == group2).should be_false should (group1 == group3).should be_false should (group2 == group3).should be_false should end it "deve armazenar número da última jogada." do dice = Dice new Dice.new dice.play play 19
  • 20. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir dice.show_number to_s.should match show_number.to_s should match(/^[1-6]*[1-6]$/) end xit "deve jogar o dado no momento que o objeto for inicializado" end class Dice def play rand rand(6) + 1 end def show_number 3 end end TROCANDO CONSTANTE POR VARIÁVEL Essa é uma regra importante no BDD. Agora você pode mudar a constante por uma variável de instância na classe dados. O teste continua passando. class Dice def play @number = rand rand(6) + 1 end def show_number @number end end 20
  • 21. Capítulo 1: Fazendo a classe Dice usando BDD JOGAR O DADO NA INICIALIZAÇÃO DO OBJETO Agora eu quero que o dado seja jogado quando ele for inicializado. O próximo teste quebrará. %w{rubygems spec lib/dice}.each {|lib| require lib} each describe Dice do it "deve ter somente números entre 1 e 6" do dice = Dice new Dice.new group = (1..1_000).collect dice.play }.join collect{ play join group.should match should match(/^[1-6]*[1-6]$/) end # Três grupos de 1000 números aleatórios devem ser diferentes um do outro it "deve mostrar números de forma aleatória" do dice = Dice new Dice.new group1 = (1..1_000).collect dice.play } collect{ play group2 = (1..1_000).collect dice.play } collect{ play group3 = (1..1_000).collect dice.play } collect{ play (group1 == group2).should be_false should (group1 == group3).should be_false should (group2 == group3).should be_false should end it "deve armazenar número da última jogada." do dice = Dice new Dice.new dice.play play dice.show_number to_s.should match show_number.to_s should match(/^[1-6]*[1-6]$/) end it "deve jogar o dado na inicialização do objeto." do Dice new.show_number to_s.should match Dice.new show_number.to_s should match(/^[1-6]*[1-6]$/) 21
  • 22. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir end end Output: ...F 1) 'Dice deve jogar o dado na inicialização do objeto.' FAILED expected "" to match /^[1-6]*[1-6]$/ ./spec/dice_spec.rb / / rb:29: Finished in 0.12371 seconds 4 examples, 1 failure USANDO O MÉTODO INITIALIZE Agora eu finalizo a classe Dice colocando o método initialize com uma mensagem para o método play. O teste passa. class Dice def initialize play end def play @number = rand rand(6) + 1 end 22
  • 23. Capítulo 1: Fazendo a classe Dice usando BDD def show_number @number end end VAMOS REFATORAR Agora eu posso fazer uma pequena refatoração no arquivo dice_spec.rb. Eu colocarei um bloco before(:each) para simplificar o código. Farei também uma refatoração no terceiro requisito: "deve armazenar número da última jogada". Agora ele funciona com uma grande quantidade de números. A lógica é se o último número é armazenado então dois grupos de 100 números são diferentes entre si. %w{rubygems spec lib/dice}.each {|lib| require lib} each describe Dice do before :each do before(:each) @dice = Dice new Dice.new end it "deve ter somente números entre 1 e 6" do group = (1..1_000).collect @dice.play }.join collect{ play join group.should match should match(/^[1-6]*[1-6]$/) end # Três grupos de 1000 números aleatórios devem ser diferentes um do outro it "deve mostrar números de forma aleatória" do group1 = (1..1_000).collect @dice.play } collect{ play group2 = (1..1_000).collect @dice.play } collect{ play group3 = (1..1_000).collect @dice.play } collect{ play (group1 == group2).should be_false should (group1 == group3).should be_false should 23
  • 24. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir (group2 == group3).should be_false should end it "deve armazenar número da última jogada." do group1 = (1..100).collect do collect @dice.play play @dice.show_number show_number end group2 = (1..100).collect do collect @dice.play play @dice.show_number show_number end (group1 == group2).should be_false should end it "deve jogar o dado na inicialização do objeto." do @dice.show_number to_s.should match show_number.to_s should match(/^[1-6]*[1-6]$/) end end BRINCANDO COM A CLASSE DICE Agora que a classe foi finalizada vamos brincar com ela no irb! >> require 'dice' => true >> dice = Dice new Dice.new => #<Dice:0xb7a64188 @number=5> >> dice.show_number show_number => 5 24
  • 25. Capítulo 1: Fazendo a classe Dice usando BDD >> dice.class class => Dice Jogando o dado somente uma vez e deixando ele de lado: >> Dice new.show_number Dice.new show_number => 2 Jogar o dado várias vezes: >> 20.times print dice.play } times{ play 21636456135236136236=> 20 Três dados: >> yellowdice = [Dice new, Dice new, Dice new] Dice.new Dice.new Dice.new => [#<Dice:0xb7a3e3d4 @number=3>, #<Dice:0xb7a3e3ac @number=5>, #<Dice:0xb7a3e384 @number=5>] >> yellowdice.each |dice| puts dice.show_number } each{ show_number 3 5 5 => [#<Dice:0xb7a3e3d4 @number=3>, #<Dice:0xb7a3e3ac @number=5>, #<Dice:0xb7a3e384 @number=5>] Jogar novamente o mesmo dado >> yellowdice.each |dice| puts dice.play } each{ play 5 2 5 => [#<Dice:0xb7a3e3d4 @number=5>, #<Dice:0xb7a3e3ac @number=2>, #<Dice:0xb7a3e384 @number=5>] Qual o maior valor entre os três dados da última jogada? 25
  • 26. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir >> puts yellowdice.collect |item| item.show_number }.max collect{ show_number max 5 => nil E qual o menor valor? >> puts yellowdice.collect |item| item.show_number }.min collect{ show_number min 2 => nil Espere um pouco. No último exemplo eu usei 3 dados?!? Ahaaa! Isso parece com os dados do jogo War. Nós criaremos os dados do jogo war no próximo capítulo. 26
  • 27. Capítulo 2: Reproduzindo os dados do jogo War Capítulo 2 Reproduzindo os dados do jogo War DESCRIÇÃO DO JOGO WAR Finalmente terminei a classe Dice! Mas eu quero algo mais excitante! Eu quero reproduzir em uma classe Ruby os dados do jogo War. Isso mesmo! Aqueles 6 dados. 3 vermelhos e 3 amarelos que representam ataque e defesa respectivamente. Eu usarei dois arrays: reddice e yellowdice para armazenar os valores dos dados. Lembrei agora que o uso dos dados depende do número de exércitos do atacante e do defensor. Mas nesse experimento eu pensarei somente na manipulação dos dados no jogo. Eles podem ser manuseados com 1, 2 ou 3 dados vermelhos contra 1, 2 ou 3 dados amarelos. Eu terei que comparar o maior valor dos dados vermelhos com o maior valor entre os dados amarelos e assim sucessivamente com os demais dados (do maior para o menor valor). Em caso de empate o amarelo vence. O vermelho só vence quando o número for maior que o amarelo. 27
  • 28. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir Bem, eu acho que é só. Vamos agir agora! TESTANDO COMPARAÇÃO DE ARRAYS Nos primeiros testes que eu fiz em meu computador, tive problemas com comparação de arrays. Paralelo a isso me lembrei que é imprescindível o uso de comparação de arrays na classe WarDice. Vamos incluir um teste de comparação de arrays no arquivo dice_spec.rb e verificar o comportamento: describe Array do it "deve ser comparável" do ([8,9,10] > [1,2,3]).should be_true should end end Output: ....F 1) NoMethodError in 'Array deve ser comparável' undefined method `>' for [8, 9, 10]:Array ./spec/dice_spec.rb:43: Finished in 0.039464 seconds 5 examples, 1 failure 28
  • 29. Capítulo 2: Reproduzindo os dados do jogo War INCLUINDO O MÓDULO COMPARABLE Para solucionar o problema anterior, apenas inclua o módulo comparable no arquivo dice.rb. Eu farei isso usando uma forma simplificada para brincar com as possibilidades do Ruby :). class Array; include Comparable; end Agora o teste passa. NÚMERO DE DADOS Agora vou trabalhar no primeiro requisito: permite a utilização de 1, 2 or 3 dados, para o ataque ou defesa.. Na classe WarDice eu vou colocar de propósito um número diferente de 1, 2, 3 para gerar um erro. describe Wardice do it "permite a utilização de 1, 2 or 3 dados, para o ataque ou defesa." do wardice = Wardice new(0, 3) Wardice.new wardice.red to_s.should match red.to_s should match(/^[1-3]$/) wardice.yellow to_s.should match yellow.to_s should match(/^[1-3]$/) end it "compara os valores do maior para o menor e salva em um array" end class Wardice attr_reader :red :yellow red, def initialize red, yellow) initialize( @red, @yellow = red, yellow 29
  • 30. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir end end Output: 'Wardice permite a utilização de 1, 2 or 3 dados, para o ataque ou defesa.' FAILED expected "0" to match /^[1-3]$/ ./spec/dice_spec.rb / / rb:50: Finished in 0.032203 seconds 8 examples, 1 failure, 2 pending RESOLVENDO O PROBLEMA DOS NÚMEROS Lógica: Se a classe for inicializada com números diferentes da lista 1-3 então as variáveis serão preenchidas com um número aleatório variando de 1 a 3. Eu farei também uma pequena refatoração no arquivo spec para que ele fique preparado para a situação em que a quantidade de dados for correta. Você pode ver a solução abaixo: class WarDice attr_reader :red :yellow red, def initialize red, yellow) initialize( @red, @yellow = red, yellow @red = rand rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @yellow = rand rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty? to_s.grep empty? end end describe WarDice do 30
  • 31. Capítulo 2: Reproduzindo os dados do jogo War it "permite a utilização de 1, 2 or 3 dados, para o ataque ou defesa." do wardice = Wardice new(0, 7) Wardice.new wardice.red to_s.should match red.to_s should match(/^[1-3]$/) wardice.yellow to_s.should match yellow.to_s should match(/^[1-3]$/) wardice2 = Wardice new(2, 3) Wardice.new wardice2.red should == 2 red.should wardice2.yellow should == 3 yellow.should end it "compara os valores do maior para o menor e salva em um array" end ARRAY EM ORDEM DECRESCENTE Esse requisito é muito importante, mas só lembrei dele agora: wardice deve fornecer os resultados dos dados vermelho e amarelo em arrays em ordem decrescente. Você pode ver a solução abaixo: describe WarDice do it "permite a utilização de 1, 2 or 3 dados, para o ataque ou defesa." do wardice = WarDice new(0, 7) WarDice.new wardice.red to_s.should match red.to_s should match(/^[1-3]$/) wardice.yellow to_s.should match yellow.to_s should match(/^[1-3]$/) wardice2 = WarDice new(2, 3) WarDice.new wardice2.red should == 2 red.should wardice2.yellow should == 3 yellow.should end it "deve fornecer os resultados dos dados vermelho e amarelo em arrays em ordem decrescente" do wardice = Wardice new(3, 3) Wardice.new wardice.reddice is_a?(Array).should be_true reddice.is_a? should 31
  • 32. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir wardice.yellowdice is_a?(Array).should be_true yellowdice.is_a? should wardice.reddice sort{|x, y| y <=> x }.should == wardice.reddice reddice.sort should reddice wardice.yellowdice sort{|x, y| y <=> x }.should == wardice.yellowdice yellowdice.sort should yellowdice end it "compara os valores do maior para o menor e salva em um array" end class wardice attr_reader :red :yellow :reddice :yellowdice red, yellow, reddice, def initialize red, yellow) initialize( @red, @yellow = red, yellow @red = rand rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @yellow = rand rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @reddice = [] @yellowdice = [] @dice = Dice new Dice.new @red.times times{|row| @reddice[row] = [@dice.play } play] @yellow.times |row| @yellowdice[row] = [@dice.play } times{ play] end end Output: 'wardice deve fornecer os resultados dos dados vermelho e amarelo em arrays em ordem decrescente' FAILE expected: [[5], [2], [4]], got: [[5], [4], [2]] (using == ==) ./spec/dice_spec.rb / / rb:63: 32
  • 33. Capítulo 2: Reproduzindo os dados do jogo War Finished in 0.035218 seconds 9 examples, 1 failure, 2 pending SOLUCIONANDO O PROBLEMA DO ARRAY EM ORDEM DECRESCENTE class WarDice attr_reader :red :yellow :reddice :yellowdice red, yellow, reddice, def initialize red, yellow) initialize( @red, @yellow = red, yellow @red = rand rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @yellow = rand rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @reddice = [] @yellowdice = [] @dice = Dice new Dice.new @red.times times{|row| @reddice[row] = [@dice.play } play] @yellow.times |row| @yellowdice[row] = [@dice.play } times{ play] @reddice.sort! sort!{|x,y| y <=> x } @yellowdice.sort! sort!{|x,y| y <=> x } end end Agora o teste passa. 33
  • 34. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir COMPARANDO OS VALORES Vamos trabalhar no último requisito: compara os valores do maior para o menor e salva em um array. describe Wardice do it "permite a utilização de 1, 2 or 3 dados, para o ataque ou defesa." do wardice = Wardice new(0, 7) Wardice.new wardice.red to_s.should match red.to_s should match(/^[1-3]$/) wardice.yellow to_s.should match yellow.to_s should match(/^[1-3]$/) wardice2 = Wardice new(2, 3) Wardice.new wardice2.red should == 2 red.should wardice2.yellow should == 3 yellow.should end it "deve fornecer os resultados dos dados vermelho e amarelo em arrays em ordem decrescente" do wardice = Wardice new(3, 3) Wardice.new wardice.reddice is_a?(Array).should be_true reddice.is_a? should wardice.yellowdice is_a?(Array).should be_true yellowdice.is_a? should wardice.reddice sort{|x, y| y <=> x }.should == wardice.reddice reddice.sort should reddice wardice.yellowdice sort{|x, y| y <=> x }.should == wardice.yellowdice yellowdice.sort should yellowdice end it "compara os valores do maior para o menor e salva em um array" do wardice = Wardice new(3, 2) Wardice.new wardice.reddice first.should > wardice.reddice last reddice.first should reddice.last wardice.attack attack wardice.result result[0].should == "Red Win" if wardice.reddice should reddice[0] > wardice.yellowdice yellowdice[0] wardice.result result[0].should == "Yellow Win" if wardice.reddice should reddice[0] <= wardice.yellowdice yellowdice[0] 34
  • 35. Capítulo 2: Reproduzindo os dados do jogo War end end A classe WarDice com os testes passando por completo: class Wardice attr_reader :red :yellow :reddice :yellowdice :result red, yellow, reddice, yellowdice, def initialize red, yellow) initialize( @red, @yellow = red, yellow @red = rand rand(3) + 1 if @red.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @yellow = rand rand(3) + 1 if @yellow.to_s grep(/^[1-3]$/).empty? to_s.grep empty? @reddice = [] @yellowdice = [] @result = [] @dice = Dice new Dice.new @red.times times{|row| @reddice[row] = [@dice.play } play] @yellow.times |row| @yellowdice[row] = [@dice.play } times{ play] @reddice.sort! sort!{|x, y| y <=> x } @yellowdice.sort! sort!{|x, y| y <=> x } end def attack @reddice.each_with_index do |item, index| each_with_index next if @yellowdice[index].nil? nil? reddice = item yellowdice = @yellowdice[index] if reddice > yellowdice @result << "Vermelho Venceu!" else 35
  • 36. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir @result << "Amarelo Venceu!" end end end end BRINCANDO COM A CLASSE WARDICE Abra o irb e digite a sequência abaixo: >> require 'dice' => true Inicialize a classe WarDice. O primeiro parâmetro é o número de dados vermelhos e o segundo é o número de dados amarelos: >> wardice = WarDice new(2, 3) WarDice.new => #<WarDice:0xb7b0b410 @yellowdice=[[6], [1], [1]], @reddice=[[3], [1]], @dice=#<Dice:0xb7b0ae0c @number=6>, yellow3, result["Yellow Win", "Yellow Win"], red2 = > Mostra o números nos dados amarelos e vermelhos: >> puts wardice.reddice reddice 3 1 => nil >> puts wardice.yellowdice yellowdice 6 1 1 => nil 36
  • 37. Capítulo 2: Reproduzindo os dados do jogo War Mostra o resultado: >> puts wardice.result result Yellow Win Yellow Win => nil A saída completa em um único comando: >> war.reddice each_with_index{ |item, index| puts "Red:#{item} Yellow:#{war.yellowdice reddice.each_with_index yellowdice[index]} - #{war.result result[index]}"} Red:3 Yellow:6 - Yellow Win Red:1 Yellow:1 - Yellow Win => [[3], [1]] Agora já temos as ferramentas para brincar. Então no próximo capítulo nós usaremos essas classes para fazer uma bela aplicação gráfica usando Shoes. 37
  • 38. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir Capítulo 3 Jogando dados com Shoes UM PEQUENO TESTE COM A CLASSE DICE E SHOES Nesse capítulo vamos criar uma interface gráfica usando Shoes e a classe WarDice, mas primeiro vamos fazer um simples teste com a classe Dice. Você deve criar o arquivo diceshoes.rb, então cole o código abaixo dentro dele e salve dentro do mesmo diretório do arquivo dice.rb. Finalmente, execute ele com o Shoes para ver o resultado. Observe que eu apenas inclui o arquivo dice.rb com um require no começo do código abaixo: require 'dice' Shoes app :title => "Teste com a classe Dice", :width => 500, :height => 500 do Shoes.app background aliceblue para "Bem Vindo! Esse é um exemplo de uso da classe Dice.", :weight => "bold" 38
  • 39. Capítulo 3: Jogando dados com Shoes dice = Dice new Dice.new # Imprime na tela os números dos dados jogados com cores aleatórias 1_000.times do times r, g, b = rand, rand, rand para dice.play :stroke => rgb **3, g** play, rgb(r** **3, b** **3), :size => "large" end end Saída: 39
  • 40. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir O CÓDIGO SHOES DO APLICATIVO QUE USA A CLASSE WARDICE Finalmente a última aplicação. copie o código seguinte em um novo arquivo e salve com o nome wardiceshoes.rb na pasta lib. Eu fiz alguns comentários através do código para facilitar a compreensão. Faça um bom experimento. require 'dice' Shoes app :title => "Dados do Jogo War", :width => 500, :height => 500 do Shoes.app background gradient black, teal ) gradient( # Listbox com a quantidade de dados vermelhos: 1, 2 or 3 para "Red", :stroke => tomato @numberreddice = list_box :items => ["1", "2", "3"], :width => 70, :choose => "3" do |list| end para " X ", :stroke => snow # Listbox com a quantidade de dados amarelos: 1, 2 or 3 @numberyellowdice = list_box :items => ["1", "2", "3"], :width => 70, :choose => "3" do |list| end para "Yellow", :stroke => yellow # Define uma posição aleatória @a = @b = @c = [] (40..200).step step(10){ |x| @a << x } (230..450).step step(10){ |y| @b << y } (80..450).step step(10){ |z| @c << z } | # Variáveis que vão armazenar os valores do objeto wardice. 40
  • 41. Capítulo 3: Jogando dados com Shoes @reddice = @yellowdice = @resulttext = [] button "Attack", :width => 80 do # Limpa a tela @dice.each |d| d.remove } each{ remove @resulttext.each |a| a.remove } each{ remove # O objeto wardice is inicializado wardice = WarDice new( @numberreddice.text to_i, @numberyellowdice.text to_i ) WarDice.new text.to_i text.to_i @reddice = wardice.reddice reddice @yellowdice = wardice.yellowdice yellowdice @result = wardice.result result # Cada dado é desenhado em uma posição aleatória @reddice.each |item| draw @a[rand each{ draw( rand(@a.length length)], @c[rand rand(@c.length length)], item.to_s to_i, 1, true ) } to_s.to_i @yellowdice.each |item| draw @b[rand each{ draw( rand(@b.length length)], @c[rand rand(@c.length length)], item.to_s to_i, 2, true )} to_s.to_i end button "Verify", :width => 80 do # Limpa a tela @dice.each |d| d.remove } each{ remove @resulttext.each |a| a.remove } each{ remove # posição inicial dos dados leftyellow = 250 leftred = 150 topred = topyellow = 100 # Cada dado é desenhado em uma posição definida @reddice.each do |item| each draw leftred, topred, item.to_s to_i, 1, false ) draw( to_s.to_i 41
  • 42. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir topred += 100 end @yellowdice.each do |item| each draw leftyellow, topyellow, item.to_s to_i, 2, false ) draw( to_s.to_i topyellow += 100 end # Posição inicial para a lista com o resultado leftresult = 300 topresult = 80 # Os resultados são impressos na tela em uma posição definida @result.each_with_index do |item, index| each_with_index @resulttext[index] = para item.to_s :stroke => snow, :top => topresult, :left => leftresult to_s, topresult += 100 end end # O método draw foi baseado no projeto Pretty Dice, escrito por Ed Heil @dice = [] def draw left, top, number, color, rotate ) draw( imagewidth = 60 imageheight = 60 i = image imagewidth, imageheight, image( :top => top - imagewidth / 2, :left => left - imagewidth / 2, :shadow => 10, :center => true ) do 42
  • 43. Capítulo 3: Jogando dados com Shoes if color == 1 strokecolor = red fillrectanglecolor = tomato filldotscolor = darkred else strokecolor = yellow fillrectanglecolor = lightgoldenrodyellow filldotscolor = chocolate end sw = 1 strokewidth sw stroke strokecolor fill fillrectanglecolor inset = 2 inset2 = 8 rect inset, inset, imagewidth-inset-sw, imageheight-inset-sw, 10 ) rect( - - - - fill filldotscolor ovalradius = 10 low = inset2 high = imagewidth - inset2 - ovalradius mid = ( imagewidth - ovalradius ) / 2 oval mid, mid, ovalradius ) if number % 2 == 1 oval( if number > 1 oval low, low, ovalradius ) oval( oval high, high, ovalradius ) oval( end 43
  • 44. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir if number > 3 oval low, high, ovalradius ) oval( oval high, low, ovalradius ) oval( end if number > 5 oval mid, low, ovalradius ) oval( oval mid, high, ovalradius ) oval( end end # fim do bloco `image` i.rotate rand 359 ) ) if rotate rotate( rand( @dice << i end end BRINCANDO COM O APLICATIVO Abaixo você pode ver o aplicativo em ação. Você deve escolher o número de dados vermelhos e amarelos no respectivo listbox. Depois clique no botão ataque para jogar os dados. Agora é só se divertir! 44
  • 45. Capítulo 3: Jogando dados com Shoes Agora clique no botão verificar para saber quem venceu! 45
  • 46. Aprenda BDD Jogando Dados! - Seu comportamento é se divertir 46