【问题标题】:Rspec: Wrong number of arguments (given 1, expected 0) and undefined method `[]' for nil:NilClassRspec:错误数量的参数(给定 1,预期为 0)和未定义的方法 `[]' 用于 nil:NilClass
【发布时间】:2019-10-24 14:37:11
【问题描述】:

我收到以下错误

第一季度。二十一点 #score 个人牌得分 "two" 为 2

 Failure/Error: expect(score(["two"])).to eq(2)

 ArgumentError:
   wrong number of arguments (given 1, expected 0)
 # ./questions/question_1.rb:78:in `score'
 # ./spec/question_1_spec.rb:80:in `block (4 levels) in <top (required)>'

对于每个数字 question_1.rb

我的代码:

def random_card
  cards = ["two", "three", "four", "five", "six", "seven",
           "eight", "nine", "ten",
           "jack", "queen", "king", "ace"]

  cards[rand(13)]
end

def move
  @hand = Array.new
  is_stick = false
  while is_stick == false
    puts "hit or stick"
    call = gets.chomp
    if call == "hit"
      @hand.push(random_card())
      score()
      puts "Score so far: " + @total.to_s
    elsif call == "stick"
      is_stick = true
    end
  end
end

def score # Line 78
  @total = 0
  @hand.each do # Line 80
    puts @values
    @total += @values[card]
  end
  @total
end

def run_game
  move()
  if @total <= 21
    puts "You scored: " + @total.to_s
  else
    puts "You busted with: " + @total.to_s
  end
end

@values = {
  "two" => 2,
  "three" => 3,
  "four" => 4,
  "five" => 5,
  "six" => 6,
  "seven" => 7,
  "eight" => 8,
  "nine" => 9,
  "ten" => 10,
  "jack" => 10,
  "queen" => 10,
  "king" => 10,
  "ace" => 11
}

这是我正在使用的 rspec 文件,这是无法更改的挑战的一部分:

require_relative "../questions/question_1"
require "mastery_answer_code_quality"

describe "Q1. Blackjack" do
  describe "#random_card" do
    it "returns all the cards in the suit" do
      expect_any_instance_of(Object).to receive(:rand).with(13).and_return(0)
      expect(random_card).to eq("two") # Does this for each card
    end
  end

  describe "#move" do
    context "user inputs hit" do
      let (:user_input) { "hit\n" }

      it 'returns `"hit"`' do
        allow_any_instance_of(Object).to receive(:gets).and_return(user_input)
        expect(move).to eq("hit")
      end
    end

    context "user inputs stick" do
      let (:user_input) { "stick\n" }

      it 'returns `"stick"`' do
        allow_any_instance_of(Object).to receive(:gets).and_return(user_input)
        expect(move).to eq("stick")
      end
    end

    context "user inputs blah and then a valid move" do
      let (:user_input) { ["blah\n", "hit\n"] }

      it 'returns valid move (`"hit"`)' do
        allow_any_instance_of(Object).to receive(:gets).and_return(*user_input)
        expect(move).to eq("hit")
      end
    end
  end

  describe "#score" do
    describe "individual cards" do
      it 'scores `"two"` as 2' do
        expect(score(["two"])).to eq(2) # does this for each card
      end
    end

    describe "adding up card scores" do
      it 'scores `"two"`, `"jack"` and `"ace"` as 23' do
        expect(score(["two", "jack", "ace"])).to eq(23)
      end
    end
  end

  describe "#run_game" do
    describe "showing score so far as game is played" do
      let (:user_input) { ["hit\n",
                           "hit\n",
                           "stick\n"] }

      let (:expected_output) { ["Score so far: 7",
                                "Score so far: 17"].join("\n.*") }

      it "`puts`es scores for two hits" do
        srand(1)
        set_user_input_and_check_expected_output
      end
    end

    describe "`puts`ing outcome of game" do
      context "player takes too many cards and busts" do
        let (:user_input) { ["hit\n",
                             "hit\n",
                             "hit\n",
                             "stick\n"] }

        let (:expected_output) { "You busted with: 28\n" }

        it "`puts`es You busted with: 28" do
          srand(1)
          set_user_input_and_check_expected_output
        end
      end

      context "player doesn't take too many cards" do
        let (:user_input) { ["hit\n",
                             "hit\n",
                             "stick\n"] }

        let (:expected_output) { "You scored: 17\n" }

        it "`puts`es You scored: 17" do
          srand(1)
          set_user_input_and_check_expected_output
        end
      end
    end

    def set_user_input_and_check_expected_output
      allow_any_instance_of(Object)
        .to receive(:gets).and_return(*user_input)

      expect { run_game }
        .to output(/#{expected_output}/m).to_stdout
    end
  end

  it "has acceptable code quality" do
    code_quality = MasteryAnswerCodeQuality.build(__FILE__)
    expect(code_quality.acceptable?).to(eq(true), code_quality.problems)
  end
end

【问题讨论】:

  • 您的错误来自@total += @values card 这一行。这是因为@values 是一个散列,要访问散列元素,您可以在散列上使用[]。你打电话给@values 就像它是一种方法一样。我不确切知道您需要在那里放置什么代码 - 测试将数组作为参数传递给该方法,这似乎不适用于代码,但这就是您应该查看的内容跨度>
  • 请参阅How to Ask 页面。请不要包含不相关的代码(像所有其他测试一样)。指出错误实际发生的位置也很有帮助,因此我们不必计算行数。
  • 您发布的错误消息不可能是由您发布的代码引起的。根据错误信息,错误发生在question_1.rb的第78行,但是您发布的代码中没有第78行确保您发布的代码和错误实际上代表了您的问题。另外,请确保它们是您问题的最小示例。重现你的问题真的需要超过 10 行代码吗?我非常怀疑。

标签: ruby rspec


【解决方案1】:

Score 在规范中获取一个数组作为参数,但您的代码没有通过它。

你需要使用这样的东西:

def score(card) # Line 78
  @total = 0
  @hand.each do # Line 80
    puts @values
    @total += @values[card]
  end
  @total
end

undefined method '[]' for nil:NilClass 表示数组或哈希为 nil,您尝试使用 [] 访问它。不幸的是,您没有共享堆栈跟踪(错误输出包含您为其他 ArgumentError 发布的被调用方法的行号)。我认为 @hand 和 @values 都没有为测试定义,请参阅底部的编辑。

您的代码使用了很多可能不需要的实例变量,例如 @hand,我建议使用局部变量,而不是使用那些,并从方法返回值,然后可以将其用作其他方法中的参数.

规范只调用 score 方法,没有别的。 因此,在方法外部定义的 @hand@values 实例变量都不可用。您需要在规范中定义它,例如如上所示,在测试中使用instance_variable_set(:@hand, ["three"])instance_variable_set(:@values, { "three" =&gt; 3 })

但由于您无法更改挑战的预定义规格,我猜这是不可能的。这当然会随后导致其他错误,这些错误也需要修复。不过,这可能是错误的方法,采取一些小步骤让事情变得绿色,稍后再重构。

我在下面的示例中添加了将实例变量设置为引用的行:

```
  it 'scores `"three"` as 3' do   
    instance_variable_set(:@hand, ["three"]) 
    instance_variable_set(:@values, { "three" => 3 }) 
    expect(score(["three"])).to eq(3)
  end
```

这是我的完整解决方案,它只是运行绿色,我没有进行任何重构。


def random_card
  cards = ["two", "three", "four", "five", "six", "seven",
           "eight", "nine", "ten", "jack", "queen", "king", "ace"]
  cards[rand(13)]
end

def move
  case gets.chomp
  when "hit"
    "hit"
  when "stick"
    "stick"
  else
    "hit"
  end
end

def score(cards)
  values = {
    "two" => 2,
    "three" => 3,
    "four" => 4,
    "five" => 5,
    "six" => 6,
    "seven" => 7,
    "eight" => 8,
    "nine" => 9,
    "ten" => 10,
    "jack" => 10,
    "queen" => 10,
    "king" => 10,
    "ace" => 11
  }
  total = 0
  current_result = 0
  cards.each do |card|
    total += values[card]
    current_result = current_result + values[card]
    puts "Score so far: #{current_result}" 
  end
  total
end

def run_game
  cards = []
  total_score = 0 
  while move == 'hit' && total_score <= 21
    cards.unshift random_card
    total_score = score(cards)
  end

  if total_score <= 21
    puts "You scored: #{total_score}"
  else 
    puts "You busted with: #{total_score}"
  end 
end

【讨论】:

  • 是的,那更好,谢谢,但是如果它在score 方法之外,它为什么不能识别我的哈希。还有你所说的堆栈跟踪是什么意思对不起我对此很陌生。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多