2

RSpec noob 需要帮助。我的大脑现在糊涂了......我正在尝试在我的代码中为这个方法创建一个基本的“我存在并且我返回一个值”测试集......

def attempt_win(board)
 @ai_winmoves.each do |k, v| # go through each win move in the ai_winmoves array located above.         
   ai_keys = v.select{ |k, v| v == "O"}.keys # grab all computer player's Os from the value hash

   intersection = ai_keys & @keys_with_o # get common elements between two arrays..note: keys_with_o = all current O's on game board

   if intersection.length >=2 # when two intersections exist it means two O's are on the board

    @answers_array << k # add to answers array per iteration

    @answers_array.each do |key|
      # answer = @anskey[@thing.last].to_sym
      puts "which moves can ai win with?"
      puts @anskey[key]
      answer = @anskey[key].to_sym
      puts "attempt win"
      puts answer

      if board.grid[answer] == " " #if win move space is empty take it
        @move = answer               
      else #check for a block move  
        # attempt_block    # handled at line 162               
      end
    end
  end
end # END @ai_winmoves.each do |k,v|

结尾

这是我的测试代码...

  describe 'attempt_win' do
    before (:each) do
      @board.grid[:b2] == "X"
    end 
    xit 'computer looks for any possible win move'
    it 'computer returns a value' do
      @player_computer.attempt_win(@board).should_not be(nil)
    end
  end

这是我遇到的 rspec 失败...

    1) Player class attempt_win computer returns a value
 Failure/Error: @player_computer.attempt_win(@board).should_not be(nil)
 NoMethodError:
   undefined method `each' for nil:NilClass
 # ./lib/player.rb:171:in `attempt_win'
 # ./spec/player_spec.rb:47:in `block (3 levels) in <top (required)>'

就是这样,但是......

如果你想查看整个类文件 player.rb 和它的测试文件 player_spec.rb 看下面...

# TODO - send error output if move already taken
# TODO - better WIN detection

class Player

attr_reader :boardpiece # i exist so game.rb can read me

def initialize(letter)
  @boardpiece = letter
end

def move_human(game, board)
  @game_two = game

  puts "human move..."

  human_move = gets.chomp
  human_symbol = human_move.to_sym
  # look for move as key in board.grid
  if board.grid.has_key?(human_symbol)
    if board.grid[human_symbol] == " "
      #puts "bingo"  
      @move = human_symbol            
    else
      puts "spot taken...try again"
      move_human(@game_two, board)
    end
  else
    puts "invalid move...try again"
    move_human(@game_two, board)
  end           
end


def move_computer(game, board)
  # ai should do three things
  # attempt win
  # block human
  # random move

  puts "computer move..."
  # all possible third moves as 'O' (computer)
  @human_winmoves = {
      :wm01 => {:a1=>"X", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>"X", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm02 => {:a1=>" ", :a2=>"X", :a3=>" ", :b1=>" ", :b2=>"X", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm03 => {:a1=>" ", :a2=>" ", :a3=>"X", :b1=>" ", :b2=>"X", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm04 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"X", :b2=>"X", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm05 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>"X", :b3=>"X", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm06 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>"X", :b3=>" ", :c1=>"X", :c2=>" ", :c3=>" "},
      :wm07 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>"X", :b3=>" ", :c1=>" ", :c2=>"X", :c3=>" "},
      :wm08 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>"X", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>"X"},
      #check those corners
      :wm09 => {:a1=>"X", :a2=>"X", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm10 => {:a1=>"X", :a2=>" ", :a3=>" ", :b1=>"X", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm11 => {:a1=>" ", :a2=>"X", :a3=>"X", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm12 => {:a1=>" ", :a2=>" ", :a3=>"X", :b1=>" ", :b2=>" ", :b3=>"X", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm13 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"X", :c1=>" ", :c2=>" ", :c3=>"X"},
      :wm14 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"X", :c3=>"X"},
      :wm15 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>"X", :c2=>"X", :c3=>" "},
      :wm16 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"X", :b2=>" ", :b3=>" ", :c1=>"X", :c2=>" ", :c3=>" "},
      #check opposites
      :wm17 => {:a1=>"X", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>"X", :c2=>" ", :c3=>" "},
      :wm18 => {:a1=>" ", :a2=>"X", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"X", :c3=>" "},
      :wm19 => {:a1=>" ", :a2=>" ", :a3=>"X", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>"X"},
      :wm20 => {:a1=>"X", :a2=>" ", :a3=>"X", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm21 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"X", :b2=>" ", :b3=>"X", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm22 => {:a1=>"X", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>"X"},
      :wm23 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>"X", :c2=>" ", :c3=>"X"},
      :wm24 => {:a1=>" ", :a2=>" ", :a3=>"X", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>"X", :c2=>" ", :c3=>" "},
      #check crazy
      :wm25 => {:a1=>" ", :a2=>"X", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>"X", :c2=>" ", :c3=>" "},
      :wm26 => {:a1=>" ", :a2=>"X", :a3=>" ", :b1=>"X", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm27 => {:a1=>" ", :a2=>"X", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>"X"},
      :wm28 => {:a1=>" ", :a2=>"X", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"X", :c1=>" ", :c2=>" ", :c3=>" "},            
      :wm29 => {:a1=>"X", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"X", :c3=>" "},
      :wm30 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"X", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"X", :c3=>" "},
      :wm31 => {:a1=>" ", :a2=>" ", :a3=>"X", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"X", :c3=>" "},
      :wm32 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"X", :c1=>" ", :c2=>"X", :c3=>" "},
      :wm33 => {:a1=>" ", :a2=>"X", :a3=>" ", :b1=>"X", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm34 => {:a1=>" ", :a2=>" ", :a3=>"X", :b1=>"X", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm35 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"X", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"X", :c3=>" "},
      :wm36 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"X", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>"X"},
      :wm37 => {:a1=>"X", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"X", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm38 => {:a1=>" ", :a2=>"X", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"X", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm39 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"X", :c1=>"X", :c2=>" ", :c3=>" "},
      :wm40 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"X", :c1=>" ", :c2=>"X", :c3=>" "}
  }

  @ai_winmoves = {
      :wm01 => {:a1=>"O", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>"O", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm02 => {:a1=>" ", :a2=>"O", :a3=>" ", :b1=>" ", :b2=>"O", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm03 => {:a1=>" ", :a2=>" ", :a3=>"O", :b1=>" ", :b2=>"O", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm04 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"O", :b2=>"O", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm05 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>"O", :b3=>"O", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm06 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>"O", :b3=>" ", :c1=>"O", :c2=>" ", :c3=>" "},
      :wm07 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>"O", :b3=>" ", :c1=>" ", :c2=>"O", :c3=>" "},
      :wm08 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>"O", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>"O"},
      #check those corners
      :wm09 => {:a1=>"O", :a2=>"O", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm10 => {:a1=>"O", :a2=>" ", :a3=>" ", :b1=>"O", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm11 => {:a1=>" ", :a2=>"O", :a3=>"O", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm12 => {:a1=>" ", :a2=>" ", :a3=>"O", :b1=>" ", :b2=>" ", :b3=>"O", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm13 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"O", :c1=>" ", :c2=>" ", :c3=>"O"},
      :wm14 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"O", :c3=>"O"},
      :wm15 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>"O", :c2=>"O", :c3=>" "},
      :wm16 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"O", :b2=>" ", :b3=>" ", :c1=>"O", :c2=>" ", :c3=>" "},
      #check opposites
      :wm17 => {:a1=>"O", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>"O", :c2=>" ", :c3=>" "},
      :wm18 => {:a1=>" ", :a2=>"O", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"O", :c3=>" "},
      :wm19 => {:a1=>" ", :a2=>" ", :a3=>"O", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>"O"},
      :wm20 => {:a1=>"O", :a2=>" ", :a3=>"O", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm21 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"O", :b2=>" ", :b3=>"O", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm22 => {:a1=>"O", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>"O"},
      :wm23 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>"O", :c2=>" ", :c3=>"O"},
      :wm24 => {:a1=>" ", :a2=>" ", :a3=>"O", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>"O", :c2=>" ", :c3=>" "},
      #check crazy
      :wm25 => {:a1=>" ", :a2=>"O", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>"O", :c2=>" ", :c3=>" "},
      :wm26 => {:a1=>" ", :a2=>"O", :a3=>" ", :b1=>"O", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm27 => {:a1=>" ", :a2=>"O", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>"O"},
      :wm28 => {:a1=>" ", :a2=>"O", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"O", :c1=>" ", :c2=>" ", :c3=>" "},            
      :wm29 => {:a1=>"O", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"O", :c3=>" "},
      :wm30 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"O", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"O", :c3=>" "},
      :wm31 => {:a1=>" ", :a2=>" ", :a3=>"O", :b1=>" ", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"O", :c3=>" "},
      :wm32 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"O", :c1=>" ", :c2=>"O", :c3=>" "},
      :wm33 => {:a1=>" ", :a2=>"O", :a3=>" ", :b1=>"O", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm34 => {:a1=>" ", :a2=>" ", :a3=>"O", :b1=>"O", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm35 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"O", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>"O", :c3=>" "},
      :wm36 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>"O", :b2=>" ", :b3=>" ", :c1=>" ", :c2=>" ", :c3=>"O"},
      :wm37 => {:a1=>"O", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"O", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm38 => {:a1=>" ", :a2=>"O", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"O", :c1=>" ", :c2=>" ", :c3=>" "},
      :wm39 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"O", :c1=>"O", :c2=>" ", :c3=>" "},
      :wm40 => {:a1=>" ", :a2=>" ", :a3=>" ", :b1=>" ", :b2=>" ", :b3=>"O", :c1=>" ", :c2=>"O", :c3=>" "}
  }
  # match current answers located in @thegrid with possible @anskey array, iterate for each item
  @anskey={
      :wm01=>"c3",:wm02=>"c2",:wm03=>"c1",:wm04=>"b3",:wm05=>"b1",:wm06=>"a3",:wm07=>"a2",:wm08=>"a1",
      :wm09=>"a3",:wm10=>"c1",:wm11=>"a1",:wm12=>"c3",:wm13=>"c3",:wm14=>"c1",:wm15=>"c3",:wm16=>"a1",
      :wm17=>"b1",:wm18=>"b2",:wm19=>"b3",:wm20=>"a2",:wm21=>"b2",:wm22=>"b2",:wm23=>"c2",:wm24=>"b2",
      :wm25=>"a1",:wm26=>"a1",:wm27=>"a3",:wm28=>"a3",:wm29=>"c1",:wm30=>"c1",:wm31=>"c3",:wm32=>"c3",
      :wm33=>"a1",:wm34=>"a1",:wm35=>"c1",:wm36=>"c1",:wm37=>"a3",:wm38=>"a3",:wm39=>"c3",:wm40=>"c3"
  }
  #
  # scan board for available move locations
  @keys_with_o = board.grid.select{ |k, v| v == "O" }.keys       # find Os on the board

  @keys_with_x = board.grid.select{ |k, v| v == "X" }.keys       # find Xs on the board

  @answers_array = [] # initialize answers array

  if board.grid[:b2] == " "   #AND center spot is empty
    ai_spot = "b2"
    # puts "ai takes center "+ai_spot
    @move = ai_spot.to_sym  #must return this answer as a symbol         
  else
    # TODO - Ai attempts win
    i = 0
    until i == 4
      attempt_win(board) #run 3x then run attempt_block
      i = i+1 # add 1 to i
      if i == 4
        puts "running attempt_block..." 
        attempt_block(board)
      end
    end
  end

  return @move # had this guy in the wrong place
end      

def attempt_win(board)
  @ai_winmoves.each do |k, v| # go through each win move in the ai_winmoves array above.         
    ai_keys = v.select{ |k, v| v == "O"}.keys # grab all computer player's Os from the value hash

    intersection = ai_keys & @keys_with_o # get common elements between two arrays..note: keys_with_o = all current O's on game board

    if intersection.length >=2 # when two intersections exist it means two O's are on the board

      @answers_array << k # add to answers array per iteration

      @answers_array.each do |key|
        # answer = @anskey[@thing.last].to_sym
        puts "which moves can ai win with?"
        puts @anskey[key]
        answer = @anskey[key].to_sym
        puts "attempt win"
        puts answer

        if board.grid[answer] == " " #if win move space is empty take it
          @move = answer               
        else #check for a block move  
          # attempt_block    # handled at line 162               
        end
      end
    end
  end # END @ai_winmoves.each do |k,v|
end

def attempt_block(board)
  puts "attempt block method - hi"
  # thing = [] # initialize thing array
  @human_winmoves.each do |k,v| # for test - go threw each win moves.
    # get common elements between two arrays..recall from above that v contains a hash
    human_keys = v.select{ |k, v| v == "X"}.keys
    # which moves can I take to block human
    intersection = human_keys & @keys_with_x

    if intersection.length >= 2
      puts "intersection"
      puts intersection
      @answers_array << k # adds a key per iteration
      puts "@answers_array << k"
      puts @anskey[k]
      @answers_array.each do |key|
        puts "which moves can ai block with?"
        puts @anskey[key]
        answer = @anskey[key].to_sym
        puts "attempt block"
        puts answer

        # if board.spot_taken?(answer)

        if board.grid[answer] != " " # spot taken
          puts "space taken can not block 2: " + answer.to_s 
        else
          puts answer.to_s+" blocked"
          @move = answer # for test - at last intersection value found...return it as move value
          return @move
        end
      end
    end
  end # END @human_winmoves.each do |k,v|
end 
end

如果您想查看整个 player_spec.rb 文件...

require 'game'
require 'board'

describe 'Player class' do  
before (:each) do
  #Dry it up
  @player_human = Player.new('X')
  @player_computer = Player.new('O')
  @board = Board.new
  @game = Game.new(@player_human, @player_computer, @board)
end

describe 'move_human' do
  before (:each) do
    # first set up my expectations         
    @player_human.should_receive(:puts).with("human move...")
    @player_human.stub(:gets).and_return("a1")
  end
  it 'receives cli input and prints text to screen' do
    # now trigger them
    @player_human.move_human("X", @board)
  end
  it 'returns a move value' do
    # now trigger them
    @player_human.move_human("X", @board).should eq(:a1)     #return the value is what I mocked?
  end     
end

describe 'move_computer' do
  it 'should print - ...computer move... - to screen' do
    # first set up my expectations
    @player_computer.should_receive(:puts).with("computer move...")
    # now trigger them
    @player_computer.move_computer("O", @board)
  end
  it 'returns expected first move b2' do
    @player_computer.move_computer("O", @board).should eq(:b2)
  end
end

describe 'attempt_win' do
  before (:each) do
    @board.grid[:b2] == "X"
  end 
  xit 'computer looks for any possible win move'
  it 'computer returns a value' do
    @player_computer.attempt_win(@board).should_not be(nil)
  end
end

describe 'attempt_block'do
  xit 'looks for a block move'
end
end
4

1 回答 1

0

如果您知道如何正确阅读,该错误会非常清楚地告诉您出了什么问题:

1) Player class attempt_win computer returns a value
 Failure/Error: @player_computer.attempt_win(@board).should_not be(nil)
 NoMethodError:
   undefined method `each' for nil:NilClass
 # ./lib/player.rb:171:in `attempt_win'
 # ./spec/player_spec.rb:47:in `block (3 levels) in <top (required)>'

这告诉你几件事:

  • 发生错误的规范行是@player_computer.attempt_win(@board).should_not be(nil).
  • 该错误是由于each在不响应该消息的对象上调用。
  • 它被调用的对象是nil
  • 错误发生在./lib/player.rb:171方法attempt_win中,或者在调用的某些内部库方法中attempt_win。(您可以使用--backtrace标志运行规范以获得完整的回溯。默认情况下,RSpec 尝试将其过滤到仅相关行以减少噪音。)

查看您的代码,该错误表明@ai_winmoves尚未初始化并且具有调用nil时间的值。attempt_win

于 2012-10-12T22:38:22.190 回答