Reputation: 25
"When a customer turns off notifications, notify_on
becomes false, and certain conditions are not met. The approach I'm considering is to check whether BellNotify.create!
is executed when notify_on
is true.
If this approach is correct, please advise how to write the code. I've tried the following:
RSpec.describe NotificationSetting, type: :model do
describe '#create_notify' do
context 'when notify_on is true' do
it 'executes BellNotify.create!' do
# Set up a notification setting where notify_on is true
setting = NotificationSetting.new(notify_on: true)
# Allow BellNotify.create! to be called
allow(BellNotify).to receive(:create!)
# Trigger the method that should call BellNotify.create!
setting.send(:create_notify)
# Check that BellNotify.create! has been received
expect(BellNotify).to have_received(:create!)
end
end
end
end
If there is another approach to test please let me know
I attempted to verify whether a method of a certain class is executed or not when specific conditions are not met.
Upvotes: 0
Views: 62
Reputation: 3585
In Ruby, predicate methods (those methods that return true or false) always end in a question mark, like this: authorized?
. You are essentially asking the object a yes/no question.
And, event handlers usually start with on_
as in on_create
.
From the context in the test, I believe you're using notify_on
as an on/off switch. I think this because you're passing true or false into the initializer. It would be more clear if you were to name the parameter notify
and use a private method named notify?
to return true or false.
It would also help to name your nouns (models) with nouns (like BellNotification
), not verbs (like BellNotify
).
Here's what canonical Ruby might look like in a class that passes your test...
class NotificationSettings
def initialize(notify: true)
@notify = notify
end
def create_notification
# do something
BellNotification.create! if notify?
end
private
def notify?
@notify == true
end
end
Then, to test this, @RobertoCarillo had it right. Here it is written without the let
or before
statements. Admittedly, this is a preference. I prefer putting the setup inside the it
block because it makes the test easy to understand without having to scroll up and down in a file with hundreds (or thousands) of lines of code...
RSpec.descripe NotificationSettings do
describe '#create_notification' do
it 'creates a BellNotification when notify? is true' do
# Arrange - setup the test
settings = NotificationSettings.new(notify: true)
allow(BellNotification).to receive(:create!)
# Act - perform the action under test (with the side effect)
settings.create_notification
# Assert - that the correct result happened
expect(BellNotification).to have_received(:create!)
end
it 'does NOT create a BellNotification when notify? is false' do
# Arrange - setup the test
settings = NotificationSettings.new(notify: false)
allow(BellNotification).to receive(:create!)
# Act - perform the action under test (with the side effect)
settings.create_notification
# Assert - that the correct result happened
expect(BellNotification).not_to have_received(:create!)
end
end
end
Upvotes: 0
Reputation: 39
I think the approach is correct, I would just make some adjustments to avoid repeating a couple of lines.
RSpec.describe NotificationSetting, type: :model do
describe '#create_notify' do
let(:notify_on) { true }
let(:settings) { NotificationSetting.new(notify_on: notify_on) }
before { allow(BellNotify).to receive(:create!) }
context 'when notify_on is true' do
it 'executes BellNotify.create!' do
setting.send(:create_notify)
expect(BellNotify).to have_received(:create!)
end
end
context 'when notify_on is false' do
let(:notify_on) { false }
it 'does not execute BellNotify.create!' do
setting.send(:create_notify)
expect(BellNotify).not_to have_received(:create!)
end
end
end
end
Upvotes: 0