Reputation: 1168
I have my method create
:
module AnswerCreator
class Creator
def initialize(answer)
@answer = answer
end
def create
test_cases_results = run_test_cases
@answer.attempt = get_attempt_number
@answer.correct = correct?(test_cases_results)
ActiveRecord::Base.transaction do
@answer.save!
save_test_cases_results(test_cases_results)
Scorer::Changer.new(@answer).change
end
ComputeAnswerSimilarityJob.perform_later(@answer)
end
...
end
end
And I have the following test to it:
it "creates the answer with the right attempt number, create the test case results and add the answer to be processed in background" do
answer_test_case_result_count = AnswerTestCaseResult.count
jobs_count = enqueued_jobs.size
user = create(:user)
team = create(:team)
question = create(:question)
create_pair(:test_case, question: question)
create(:answer, question: question, user: user, team: team)
answer = build(:answer, question: question, user: user, team: team)
# These answers must be ignored >>
create(:answer, question: question, user: user)
create(:answer, question: question, team: team)
create(:answer, user: user, team: team)
described_class.new(answer).create
expect(answer.new_record?).to be_falsey
expect(answer.attempt).to eq 2
expect(AnswerTestCaseResult.count).to eq answer_test_case_result_count + 2
expect(enqueued_jobs.size).to eq jobs_count + 1
end
This Creator
class deals with the creation logic when an Answer object is created. My Changer
class deals with the score logic associated to an Answer object. I don't want to test this logic inside the Creator
, but I would like to ensure that the change
method from Changer
is called.
How can I test this?
Upvotes: 0
Views: 961
Reputation: 26758
So you have this line of code you want to test:
Scorer::Changer.new(@answer).change
My initial thought is to recommend allow_any_instance_of, but as you see in that link, the RSpec team advises against it. If you wanted to, though, you could putting this inside the test case, before calling Creator#create
:
expect_any_instance_of(Scorer::Changer).to receive(:change).and_call_original
Withoug expect_any_instance_of
, to the best of my knowledge you'd have to stub the constructor:
fake_answer = "???" # change to the value of 'answer' in your test case
fake_changer = Scorer::Changer.new fake_answer
expect(Scorer::Changer).to receive(:new).and_return fake_changer
expect(fake_changer).to receive(:change).and_call_original
This sort of thing is a little tedious, but is what happens when functions have a lot going on in terms of private state. Like, for example, what if you moved the Scorer::Changer.new
call to Creator#initialize
?
attr_reader :changer
def initialize(answer)
@answer = answer
@changer = Scorer::Changer.new @answer
end
Then you need to do a little less stubbing:
fake_answer = "???"
creator = AnswerCreator::Creator.new fake_answer
expect(creator.changer).to receive(:change).and_call_original
creator.create
Upvotes: 2