Rajkaran Mishra
Rajkaran Mishra

Reputation: 4952

RSpec: Method stub in factory bot definition file

I have a model, which is using attr_encrypted gem to encrypt the password.

class Credential < ApplicationRecord
  validates :user_name, presence: true
  enum credential_type: { windows: 1, linux: 2 }

  attr_encrypted :user_pass, key: :encryption_key

  def encryption_key
    # Some complex logic
  end
end

I am learning to write test cases and my factory for the above looks like this:

FactoryBot.define do
  factory :credential do
    user_name { "rmishra" }
    user_pass { "secret" }
    credential_type { "linux" }
    encryption_key { "abcdefghijklmnopqrstuvw123456789" }
  end
end

My spec file looks like:

RSpec.describe Credential, type: :model do
  let(:credential) { create(:credential) }
  ...
end

How do I stub encryption_key method in factory definition, which is getting used at the time of create?

Upvotes: 1

Views: 3140

Answers (1)

Fito von Zastrow
Fito von Zastrow

Reputation: 760

Since encryption_key is not an attribute on your model, you can't configure it in your factory.

encryption_key is called automatically by the attr_encrypted gem when you assign user_pass to a Credential object. In this case that's done by the factory.

I would move the logic in your encryption_key method into a class to facilitate testing:

class Credential < ApplicationRecord
  validates :user_name, presence: true
  enum credential_type: { windows: 1, linux: 2 }

  attr_encrypted :user_pass, key: :encryption_key

  def encryption_key
    EncryptionKeyGenerator.generate # or whatever name makes more sense
  end
end

Then, in my test, I would stub the EncryptionKeyGenerator:

RSpec.describe Credential, type: :model do
  let(:credential) { create(:credential) }
  let(:encryption_key) { "abcdefghijklmnopqrstuvw123456789" }

  before do
    allow(EncryptionKeyGenerator).to receive(:generate).and_return(encryption_key)
  end

  ...
end

Encapsulating your encryption key generation logic into a separate object decouples it from your model, allowing you to easily test that logic without having to create a Credential object.

Upvotes: 2

Related Questions