Home > OS >  RSpec test not passing when I know the method is being called
RSpec test not passing when I know the method is being called

Time:09-15

I have the following class:

class UserRewards
  def self.grant(reward_id:, submission_id:, user_id:)
    puts 'Hello from UserRewards.grant'
    debugger
    ActiveRecord::Base.transaction do
      puts 'ActiveRecord::Base.transaction'
    end
  end
end

And the following test:

require 'rails_helper'

RSpec.describe UserRewards do
  describe '.grant' do
    it 'grants a reward to a user' do
      user = build_stubbed(:user)
      submission = build_stubbed(:submission)
      reward = build_stubbed(:reward)

      UserRewards.grant(
        reward_id: reward.id,
        submission_id: submission.id,
        user_id: user.id,
      )

      expect(ActiveRecord::Base).to receive(:transaction)
    end
  end
end

I simply want to verify that ActiveRecord::Base has received :transaction, when I run the test, but no matter what I do, or how I try to restructure this test, I always get the following failure:

1) UserRewards.grant grants a reward to a user
    Failure/Error: expect(ActiveRecord::Base).to receive(:transaction)

      (ActiveRecord::Base (class)).transaction(*(any args))
          expected: 1 time with any arguments
          received: 0 times with any arguments

I've verified the method is being run via the debugger:

(rdbg) n    # next command
[1, 10] in ~/workspace/my-app/lib/services/user_rewards.rb
     1| class UserRewards
     2|   def self.grant(reward_id:, submission_id:, user_id:)
     3|     debugger
     4|     ActiveRecord::Base.transaction do
=>   5|       puts 'ActiveRecord::Base.transaction'
     6|     end
     7|   end
     8|
     9|   def self.revoke(reward_id:, submission_id:, user_id:)
=>#0    block in grant at ~/workspace/my-app/lib/services/user_rewards.rb:6
#1  block in within_new_transaction at ~/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/activerecord-7.0.1/lib/active_record/connection_adapters/abstract/transaction.rb:319
# and 74 frames (use `bt' command for all frames)

I know I must be doing something wrong here. I don't have to stub the method on ActiveRecord::Base, do I? I'm not the most proficient tester, but I'm trying to get better. And headaches like this are what always put me off from having well tested code...

CodePudding user response:

If you just need to know that a transaction was called you can stub this method and then check that it was called. Your it is very fat, it's better to use AAA-principle

require 'rails_helper'

describe UserRewards do
  describe '.grant' do
    let(:user) { build_stubbed(:user) }
    let(:submission) { build_stubbed(:submission) }
    let(:reward) { build_stubbed(:reward) }

    before do
      allow(ActiveRecord::Base).to receive(:transaction)

      described_class.grant(
        reward_id: reward.id,
        submission_id: submission.id,
        user_id: user.id,
      )
    end

    it 'calls database transaction' do
      expect(ActiveRecord::Base).to have_received(:transaction).once
    end
  end
end
  • Related