Spance
Spance

Reputation: 607

Rspec testing a before_create hook

I'm trying to test the set_random_token method seen below from my model

class Invitation < ActiveRecord::Base

      has_and_belongs_to_many :users

      validates :name, presence: true, uniqueness: true
      validates :number_of_uses, presence: true, numericality: true
      validates :token, presence: true, uniqueness: true, format: /\A[0-9A-F]+\z/i
      before_create :set_random_token

      private

      def set_random_token
        random_hex = SecureRandom.hex(8)
        self.token = random_hex
      end

    end

Here is the piece in my invitation_spec

it 'verifies that the token is set' do
    @invitation = Invitation.new
    @invitation.save
    expect(@invitation.token).not_to be_empty
end

And here is the error I'm getting

  2) Invitation verifies that the token is set
     Failure/Error: expect(@invitation.token).not_to be_empty
       expected  to respond to `empty?`
     # ./spec/models/invitation_spec.rb:37:in `block (2 levels) in <top (required)>'

I'm pretty new to Rails, so I apologize if the answer is extremely obvious.

Upvotes: 1

Views: 1375

Answers (2)

Dave Kinkead
Dave Kinkead

Reputation: 47

From the Rails Documentation:

The following methods trigger validations, and will save the object to the database only if the object is valid:

  • save

In your test, you are instantiating an empty Invitation but Invitation has a number of validations on it which would make an empty one invalid.

Try this instead:

@invitation = Invitation.create({name: 'something unique', number_of_uses: 5})
expect(@invitation.token).not_to be_empty
@invitation.save

Upvotes: 0

MilesStanfield
MilesStanfield

Reputation: 4639

I've seen times where checking the contents of an attribute/column from a local or instance variable of a record didn't yield the same expected result. The workaround I've used in the past is to query for the record with .first and check the column on that.

To ensure you are actually getting the correct record you add a expect(Table.count).to eq 0 at the beginning.

Give this a try

it 'verifies that the token is set' do
  expect(Invitation.count).to eq 0
  Invitation.new().save(validate: false)
  expect(Invitation.count).to eq 1
  expect(Invitation.first.token).not_to be_empty
end

Upvotes: 2

Related Questions