简体   繁体   中英

Test failing - one class method to call another (“expected: 1 time with arguments, received 0 times”)

My problem:

I'm trying to stub a class method that returns an instance of that class, but I'm getting the following error for the test entitled "creates an instance with CSV data":

Failures:

  1) QuestionData.load_questions creates an instance with CSV data
     Failure/Error: expect(question_data_class).to receive(:new).with(data).and_return(question_data_instance)

       (QuestionData (class)).new([{:time_limit=>10, :text=>"Who was the legendary Benedictine monk who invented champagne?", :correct_...the world?", :correct_answer=>"Lake Superior", :option_2=>"Lake Victoria", :option_3=>"Lake Huron"}])
           expected: 1 time with arguments: ([{:time_limit=>10, :text=>"Who was the legendary Benedictine monk who invented champagne?", :correct_...the world?", :correct_answer=>"Lake Superior", :option_2=>"Lake Victoria", :option_3=>"Lake Huron"}])
           received: 0 times

The context:

The code (shown below) works - QuestionData.load_questions loads data from a CSV file and calls QuestionData.new with the data as an argument. My test for the .load_questions method however, is giving the above error. When it's called, the double of the QuestionData class isn't receiving the stub of .new with the data double.

I've tried researching how to test stubs that return another stub or an instance, but can't seem to find a relevant answer.

I'd really appreciate any help or advice, thanks very much in advance!

The code:

require "csv"

class QuestionData

  attr_reader :questions

  def initialize(questions)
    @questions = questions
  end

  def self.load_questions(file = './app/lib/question_list.csv', questions = [])
    self.parse_csv(file, questions)
    self.new(questions)
  end

  def self.parse_csv(file, questions)
    CSV.foreach(file) do |row|
      time_limit, text, correct_answer, option_2, option_3 = row[0],
       row[1], row[2], row[3], row[4]
      questions << { time_limit: time_limit, text: text,
        correct_answer: correct_answer, option_2: option_2, option_3: option_3
      }
    end
  end

end

The test file:

require './app/models/question_data'

describe QuestionData do

  subject(:question_data_instance) { described_class.new(data) }
  let(:question_data_class) { described_class }
  let(:CSV) { double(:CSV, foreach: nil) }
  let(:questions) { [] }
  let(:file) { double(:file) }
  let(:data) do
    [{
      time_limit: 10,
      text: "Who was the legendary Benedictine monk who invented champagne?",
      correct_answer: "Dom Perignon",
      option_2: "Ansgar",
      option_3: "Willibrord"
      },
      {
        time_limit: 12,
        text: "Name the largest freshwater lake in the world?",
        correct_answer: "Lake Superior",
        option_2: "Lake Victoria",
        option_3: "Lake Huron"
      }]
  end

  describe '#questions' do
    it "has an array of question data from CSV" do
      expect(question_data_instance.questions).to eq(data)
    end
  end

  describe '.parse_csv' do
    it "parses CSV data into hash data" do
      expect(CSV).to receive(:foreach).with(file)
      question_data_class.parse_csv(file, questions)
    end
  end

  describe '.load_questions' do
    it "calls '.parse_csv' method" do
      expect(question_data_class).to receive(:parse_csv).with(file, questions)
      question_data_class.load_questions(file, questions)
    end

    it "creates an instance with CSV data" do
      allow(question_data_class).to receive(:load_questions).with(file, questions).and_return(question_data_instance)
      allow(question_data_class).to receive(:new).with(data).and_return(question_data_instance)
      expect(question_data_class).to receive(:new).with(data).and_return(question_data_instance)
      question_data_class.load_questions(file, questions)
    end
  end

  describe '.new' do
    it "creates a new instance with CSV data" do
      expect(question_data_class).to receive(:new).with(data).and_return(question_data_instance)
      question_data_class.new(data)
    end
  end

end

The thing is that you are stubbing the call on:

allow(question_data_class).to receive(:load_questions).with(file)

If you still want that the call executes you need to add a:

and_call_original

Therefore the original method will be executed and your code will call the new method on the original block.

But the thing is that you don't need to stub the class you just need to change the stubs because you are calling the method on a double, and it will try to execute it in a class, so you might need to change your second test to:

describe '.load_questions' do
  it "creates an instance containing CSV data" do
    expect(described_class).to receive(:new).with(data).and_return(question_data_instance)
    described_class.load_questions(file)
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM