如何为一种方法编写rspec测试

时间:2012-10-18 20:30:42

标签: ruby rspec

我将此方法作为更大类的一部分。我正在尝试为它编写一个测试,但我是rspec的新手,我有点难过......如果我在9次循环中注释掉所有内容,我可以测试'drawgrid'。但如果我取消注释该代码,则当前测试失败。我需要测试播放方法...运行游戏。它将'drawgrid'...运行游戏序列9次,每次转弯后放置'drawgrid'。但我不知道该怎么做。任何指针都非常感谢。

以下是播放方法及其当前规格

      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

2 个答案:

答案 0 :(得分:3)

一般来说,我觉得您的代码和测试都试图在一种方法中做太多。关于你的游戏方法的有趣的一点并不是那个循环内部发生的9倍。我对重构的第一个建议是将该循环内部的内容转换为一个名为“take_turn”的方法或类似的方法。

然后你可以为单回合发生的事情编写规格。并且,play方法的规范将测试take_turn方法被调用9次。

这并不是说你不能保持你的代码的方式,并为它编写一个有效的测试...你只是不能对你正在测试的东西进行超级手术。

希望有所帮助。

答案 1 :(得分:3)

我是戴夫说的第二个。尽量简化。基本上,如果您可以简化您的游戏方法,它将简化您的测试。现在播放关注每个回合的实现细节。推送这些细节,您的测试可以变得更容易编写和更细粒度。我不是最好的,我对此并不十分满意,但希望下面的代码能够推动你朝着正确的方向发展:

#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