I'm using Rspec to test the case when user change password, mail will be sent. And I want to check that only 1 mail is sent. I don't want use Action::Mailer.deliveries
to check, instead I want to check that whether method is called and how much.
On searching I found Test Spy
from rspec mock: https://github.com/rspec/rspec-mocks#test-spies
describe 'PUT /email' do
include_context 'a user has signed in', { email: 'old-email@example.com', password: 'correct_password' }
context 'correct new email, correct password' do
before do
allow(user).to receive(:send_reconfirmation_instructions)
end
it do
should == 302
expect(user.reload.unconfirmed_email).to eq 'new-email@example.com'
expect(user).to receive(:send_reconfirmation_instructions).once
end
end
end
But I got error:
Failure/Error: expect(user).to receive(:send_reconfirmation_instructions)
(#<User id: 1269, email: “old-email@example.com”, created_at: “2019-08-27 03:54:33", updated_at: “2019-08-27 03:54:33”...“>).send_reconfirmation_instructions(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
send_reconfirmation_instructions
this function is from devise: https://github.com/plataformatec/devise/blob/master/lib/devise/models/confirmable.rb#L124-L130
I did binding.pry
and I'm sure that the test jump inside this function but rspec still failed.
Edit: I could make it kind of work by writing like this:
describe 'PUT /email' do
include_context 'a user has signed in', { email: 'old-email@example.com', password: 'correct_password' }
context 'correct new email, correct password' do
before do
expect_any_instance_of(User).to receive(:send_reconfirmation_instructions).once
end
it do
should == 302
expect(user.reload.unconfirmed_email).to eq 'new-email@example.com'
# expect(user).to receive(:send_reconfirmation_instructions).once
end
end
end
However I got another error:
Failure/Error:
(#<User user_id: 1418, email: “old-email@example.com”...“>).send_reconfirmation_instructions(#<User user_id: 1418, email: “old-email@example.com” ...“>)
expected: 1 time with any arguments
received: 2 times with arguments: (#<User user_id: 1418, email: “old-email@example.com”, id: 1323...“>)
The line where you're checking that the user has received the message should read:
expect(user).to have_received(:send_reconfirmation_instructions).once
instead of:
expect(user).to receive(:send_reconfirmation_instructions).once
The former where you say expect(obj).to have_received(:msg)
requires you to assert that the message was called, as you intended to do.
The latter, on the other hand, where you say expect(obj).to receive(:msg)
is a way to set up the expectation before the action, ie in lieu of the allow(obj).to receive(:msg)
without requiring to assert that it was called after the action. After the spec ran, it will automatically assert whether it was called.
This explains the error you're getting when specifying
expect(user).to receive(:send_reconfirmation_instructions).once
as no code after that line sends that message to user
, which gets verified after the spec.
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.