Rspec: Неверное количество аргументов (задано 1, ожидается 0) и неопределенный метод `[] 'для nil: NilClass - PullRequest
0 голосов
/ 24 октября 2019

Я получаю следующую ошибку в

Q1. Блэкджек # баллы отдельных карт "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 Iиспользую, что является частью задачи, не может быть изменено:

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

1 Ответ

0 голосов
/ 25 октября 2019

Score получает массив в качестве параметра в спецификации, но ваш код не передает его. Чтобы исправить это, вам нужно использовать что-то вроде этого (см. Параметр card)

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, к которому вы пытаетесь получить доступ, используя []. К сожалению, вы не публикуете в своем сообщении никаких подробностей / стековых трасс. Я думаю, что ни @hand, ни @values ​​не определены где-то для теста, см. Edit внизу.

Обратите внимание, ваш код использует много переменных экземпляра, таких как @hand, которые, возможно, не нужны, яd предлагает использовать вместо них локальные переменные и возвращать значения из методов, которые затем можно использовать в качестве параметров в других методах


Редактировать:

  1. Спецификации вызывают только метод оценки и ничего больше. Поэтому ни @hand, ни @values переменные экземпляра, определенные вне метода, недоступны. Вы должны определить это в спецификациях, например, используя instance_variable_set(:@hand, ["three"]) или instance_variable_set(:@values, { "three" => 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
    
  2. Отслеживание стека - это ошибка, содержащая номера строк для вызываемых методов, которые вы опубликовалидля другого ArgumentError. Теперь я посмотрел на ошибки локально, не беспокоясь.

Вот мое решение, которое просто работает, я не проводил никаких рефакторингов, я надеюсь, что вы можете работать или учиться уэто также:


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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...