1

私はこのメソッドをより大きなクラスの一部として持っています。私はそれのテストを書き込もうとしていますが、rspecは初めてで、ちょっと困惑しています... 9.timesループですべてをコメントアウトすれば、「drawgrid」をテストできます。しかし、そのコードのコメントを外すと、現在のテストは失敗します。playメソッドが...ゲームを実行することをテストする必要があります。それが「ドローグリッド」を置くこと...各ターンの後に「ドローグリッド」を置くことでゲームシーケンスを9回実行します。しかし、これを行う方法がわかりません。どんなポインタでも大歓迎です。

以下は再生方法と現在の仕様です

      def play
        #draw the board
        puts drawgrid

        #make a move
        turn = 0

        9.times do

          if turn.even?

            @player = @player_h.move_human("X", @board)

            @move = @player.to_sym
            @marker = @player_h.boardpiece

            does_move_exist(@move,@marker)
            is_a_human_win(@board)

          else

            @player = @player_c.move_computer("O", @board)

            @move = @player
            @marker = @player_c.boardpiece

            does_move_exist(@move,@marker)
            is_a_computer_win(@board)

          end

          puts drawgrid

          turn += 1
        end # 9.times ends
      end

現在の仕様...

      describe 'play method' do
        it 'draws the game grid' do
          @player_human = Player.new('X')
          @player_computer = Player.new('O')
          @board = Board.new
          @game = Game.new(@player_human, @player_computer, @board)

          @game.should_receive(:puts).with("\na  | |  \n----------\nb  | |  \n----------\nc  | |  \n----------\n  1 2 3\n")

          @game.play
        end
      end
      describe '9.times' do
        it 'runs game sequence 9 times...once per board spot' do
          @player_human2 = Player.new('X')
          @player_computer2 = Player.new('O')
          @board2 = Board.new
          @game2 = Game.new(@player_human2, @player_computer2, @board2)

          turn = 0       
          9.times do
            if turn.even?
              @player_human2.should_receive(:puts).with("human move...")
              @player_human2.stub(:gets).and_return("b2")
            else
              @player_human2.should_receive(:puts).with("computer move...")
              @player_human2.stub(:gets).and_return("a1")
            end
            turn += 1
          end
        @game2.play
        end
      end
4

2 に答える 2

3

一般的に、私はあなたのコードとあなたのテストの両方が1つの方法であまりにも多くのことをしようとしているように感じます。あなたのプレイメソッドについての興味深い点は、そのループ内で起こることほど9倍ではありません。そのループ内にあるものを「take_turn」または同様のものと呼ばれるメソッドに変換することであるリファクタリングの私の最初の提案。

次に、1ターンで何が起こるかについての仕様を書くことができます。また、playメソッドの仕様では、take_turnメソッドが9回呼び出されることをテストします。

それはあなたがあなたのコードをそれがそうであるように保ちそしてそれのために効果的なテストを書くことができなかったということではありません...あなたはあなたがテストしているものについて超外科的になることができないだけです。

お役に立てば幸いです。

于 2012-10-18T21:07:43.433 に答える
3

私はデイブが言うことを2番目にしています。単純化してみてください。基本的に、プレイ方法を単純化できれば、テストも単純化されます。現在、プレイは各ターンの実装の詳細に関係しています。これらの詳細を押し下げると、テストを書きやすく、よりきめ細かくすることができます。私は最高ではありません、そして私はまだこれにあまり満足していません、しかしうまくいけば、以下のコードはあなたを正しい方向に押し進めます:

#play.rb

class Board
end

class Player
  def initialize(symbol)
    @symbol = symbol
  end

  def take_turn
  end
end

class Game
  def initialize(player1, player2, board)
    @player1, @player2, @board = player1, player2, board
  end 

  def play
    drawgrid

    (0...9).each do |turn|
      turn.even? ? @player1.take_turn : @player2.take_turn
      drawgrid
    end
  end

  def drawgrid
  end
end

そしてテストファイル:

#play_spec.rb
require './play.rb'

describe '#play' do
  before do
    @player1 = Player.new('X')
    @player2 = Player.new('O')
    @game = Game.new(@player1, @player2, Board.new)
  end

  it 'draws the game grid' do
    @game.should_receive(:drawgrid).at_least(:once)
    @game.play
  end

  it 'runs game sequence 9 times...once per board spot' do
    @player1.stub(take_turn: true)
    @player2.stub(take_turn: true)
    @player1.should_receive(:take_turn).exactly(5).times
    @player2.should_receive(:take_turn).exactly(4).times
    @game.play
  end
end
于 2012-10-19T19:12:21.233 に答える