【问题标题】:rspec test if method is calledrspec 测试是否调用方法
【发布时间】:2016-07-14 14:23:17
【问题描述】:

我不知道如何编写一个可以工作的测试,它也不会在我的 CL 脚本中运行任何东西。当@counter 为9 时,应该触发#tie_game?但它不起作用。 @counter 被初始化为 0 并且每次玩家在游戏板上放置 X 或 O 时递增 1。一旦@counter 为 9,我如何测试它调用 tie_game?而当它小于9时它不会?

def initialize(player1, player2)
    @player1 = player1
    @player2 = player2
    @rows = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

    @wins = [1, 2, 3], [4, 5, 6], [7, 8, 9], 
        [1, 4, 7], [2, 5, 8], [3, 6, 9],
        [1, 5, 9], [3, 5, 7]

    @selected_numbers = []
    @counter = 0
end

def increment_counter
    @counter += 1

    if @counter == 9
        tie_game?
    end
end

def tie_game?
    puts "The game was a tie. Nicely played #{@player1} & #{@player2}!"
    play_again  
end

我试过这个:你能解释为什么它不起作用吗?

describe "increment_counter" do
    context "counter equals 9" do
        it "calls tie_game?" do
            game.instance_variable_set(:@counter, 9)
            allow(game).to receive(:increment_counter)
            #expect(STDOUT).to receive(:puts).with("The game was a tie. Nicely played #{@player1} & #{@player2}!")
            expect(game).to receive(:tie_game?)
        end
    end
    context "counter is less than 9" do
        it "does not call tie_game?" do
            game.instance_variable_set(:@counter, 4)
            game.increment_counter
            expect(game).not_to receive(:tie_game?)  
        end
    end
end

【问题讨论】:

  • 我在发布答案后看到了您的编辑。它对您不起作用的原因是您在设置期望值后从未真正调用过您的代码。在测试是否发送和接收消息时,您必须颠倒期望/运行顺序。
  • 好的太棒了。非常感谢您的帮助,这肯定更有意义

标签: ruby testing rspec


【解决方案1】:

RSpec Mocks 为你做这件事。

describe TicTacToe do
  let(:game) { TicTacToe.new }

  context "after fewer than 9 moves" do
    it "does not call tie_game?" do
      expect(game).not_to receive(:tie_game?)
      8.times { game.increment_counter }
    end
  end

  context "after 9 moves" do
    it "calls tie_game?" do
      expect(game).to receive(:tie_game?)
      9.times { game.increment_counter }
    end
  end
end

更多详情请见https://relishapp.com/rspec/rspec-mocks/v/3-5/docs/basics/expecting-messages

顺便说一句,tie_game?后面可能不应该有问号。领带游戏?表示它正在检查游戏是否平局。

【讨论】:

  • 非常感谢,因为这个我可以删除很多代码。
  • 旁注,没有双打就不能使用have_received。你必须像这个例子一样测试receive
【解决方案2】:

这是一个有趣的问题。我的方法是猴子修补类,重新定义方法tie_game?,这会产生一些可以通过测试检测到的副作用。

因为我没有看到你的班级名称,所以我们就叫它Foo

首先,创建一个模块,比如TrackMethods

module TrackMethods
  # A global variable that stores how many times a method is called.
  $method_calls = Hash.new(0)

  def self.[](*method_names)
    Module.new do
      method_names.each do |name|
        define_method name do |*args, &block|
          $method_calls[name] += 1
          super(*args, &block)
        end
      end
    end
  end
end

然后在 spec_helper.rb

Foo.prepend TrackMethods[:tie_game?]

之后,在你的测试中,你可以

expect($method_calls[:tie_game?]).to be > 0

【讨论】:

  • 感谢您的回复,我刚刚对我的 OP 进行了编辑
猜你喜欢
  • 2014-05-05
  • 1970-01-01
  • 2014-02-11
  • 1970-01-01
  • 2012-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多