简体   繁体   中英

Rspec test call method send reconfirmation instruction

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM