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.