I have a class structure in a Rails (v7) app that looks like this:
# app/services/email_notifier.rb
class EmailNotifier
def notify(template_data)
# do things with email client
end
end
# app/services/email_notifier/template_data.rb
class EmailNotifier
class TemplateData
def fill_in
# do things with template and email client
end
end
end
# app/services/notification_service.rb
class NotificationService
def call
template_content = EmailNotifier::TemplateData.new(name: 'John Doe')
EmailNotifier.notify(template_content)
end
end
And what I'm trying to do is verify that the class methods are called:
# spec/services/notification_service.rb
require 'rails_helper'
RSpec.describe NotificationService do
subject(:service) { described_class.new }
let(:email_notifier) { class_double(EmailNotifier).as_stubbed_const }
let(:email_template_class) { class_double(EmailNotifier::TemplateData).as_stubbed_const }
let(:email_template) { instance_double(EmailNotifier::TemplateData) }
before do
allow(email_notifier).to receive(:notify)
allow(email_template_class).to receive(:new).and_return(:email_template)
allow(email_template).to receive(:fill_in)
end
it 'fills the template in' do
service.call
expect(email_template).to have_received(:fill_in)
end
end
When I run rspec, I get this error:
NameError:
uninitialized constant #<ClassDouble(EmailNotifier) (anonymous)>::TemplateData
template_content = EmailNotifier::TemplateData.new
Now, I understand that I could be facing a problem from different origins:
As I suspect that what is happening is 2., the question is how can I make this kind of stub happen? Is this possible? Am I facing it in a wrong way?
I'm not sure stub_const
works either as I expect in this spec.
Why mock the classes when you're stubbing the methods?
allow(EmailNotifier).to receive(:notify)
allow(EmailNotifier::TemplateData).to receive(:fill_in)