ruby Rspec测试失败

a8jjtwal  于 2023-02-03  发布在  Ruby
关注(0)|答案(1)|浏览(190)

我正在尝试测试#game_over?方法,该方法使用instance_double调用Board类中的#check_row,但测试失败。

describe '#game_over' do
    subject(:game_over) { described_class.new }
    let(:board) { instance_double(Board) }
    context 'when #game_over is called' do
      it 'calls #check_row in Board' do
        game_over.game_over?
        expect(board).to receive(:check_row)
        #game_over.game_over?
      end
    end
  end

我希望#game_over?调用Board类中的#check_row,但测试失败。下面是我正在测试的方法:

def game_over?
    return true if @board.check_row || @board.check_column || @board.check_diagonal || @board.check_antidiagonal

    false
  end

以下是失败消息:

1) Game#game_over when #game_over is called calls #check_row in Board
     Failure/Error: expect(board).to receive(:check_row)
     
       (InstanceDouble(Board) (anonymous)).check_row(*(any args))
           expected: 1 time with any arguments
           received: 0 times with any arguments

下面是我的Game#initialize方法:

def initialize
    @board = Board.new
  end
vs3odd8k

vs3odd8k1#

Game类中的Board示例和测试中的板模拟是不同的示例,因此测试失败。
我建议使用依赖注入来控制Game中的电路板示例,并像这样更改初始化器和测试:

# in the Game class
def initialize(board = nil)
  @board = board || Board.new
end

# in your spec
describe '#game_over?' do
  subject(:game) { described_class.new(board) } # inject the board stub here
  
  let(:board) { instance_double(Board) }

  before { allow(board).to receive(:check_row).and_return(true) } 

  it 'delegates to Board#check_row' do
    game.game_over?
    
    expect(board).to have_received(:check_row)
  end
end

注:
我认为当前形式的测试没有增加多少价值,而且它测试的是您不应该真正关心的内部实现细节。
测试在Game中的内部@board对象上调用特定方法没有任何好处。事实上,测试这种内部行为将使以后在需求改变或实现新特性时重构代码变得更加困难。
相反,我建议集中测试方法在某些前提条件下返回预期结果(而不是如果以及如何从另一个对象接收结果)。
在本例中,我建议不要测试board.check_row是否被调用,而是测试Board#game_over?是否因为调用而返回预期结果,如下所示:

# in the Game class
def initialize(board = nil)
  @board = board || Board.new
end

# in your spec
describe '#game_over?' do
  subject(:game) { described_class.new(board) }    # inject the board stub here
  
  let(:board) { instance_double(Board) }

  context 'with the board row check returns true' do
    before { allow(board).to receive(:check_row).and_return(true) }

    it 'is game over' do
      expect(game).to be_game_over
    end
  end
end

相关问题