1

Hi i am working on RoR project with ruby-2.5.0 and rails 5.0. I have a model forgot_password where a class method is defined to create a record as follows:-

forgot_password.rb
# frozen_string_literal: true

class ForgotPassword < ApplicationRecord
  before_create :create_token

  def self.create_record
    self.create!(expiry: Time.zone.now +
                 ENV['VALIDITY_PERIOD'].to_i.hours)
  end

  private

  def create_token
    self.token = SecureRandom.urlsafe_base64(nil, false)
  end
end

I want to write unit testing for it using stub or factory_girl gem.

spec/models/forgot_password_spec.rb
# frozen_string_literal: true

require 'rails_helper'

describe ForgotPassword do
  let(:forgot_password) do
    described_class.new()
  end

  describe 'create_record' do
    context 'with forgot_password class' do
      subject { forgot_password.create_record.class }

      it { is_expected.to eq ForgotPassword }
    end
  end
end

But its throwing error undefined method create_record for #<ForgotPassword:0x000000000622bc98> Please help me how can i test my model. Thanks in advance.

3
  • Stop instantiating an instance of the described class? Commented Mar 28, 2018 at 16:05
  • sorry i didnot get your point Commented Mar 28, 2018 at 16:17
  • how can i test my model where i have a class method and before_create callback? Commented Mar 28, 2018 at 16:18

2 Answers 2

1

What you have written is a factory method (a class method that returns an instance) you should call it and write expectations about the instance returned:

describe ForgotPassword do
  describe ".create_record" do
    subject { described_class.create_record! }
    it { is_expected.to be_an_instance_of(described_class) }
    it "sets the expiry time to a time in the future" do
      expect(subject.expiry > Time.now).to be_truthy
    end
  end
end

However if what you really are looking to do is set a computed default value then there is a much less clunky way:

class ForgotPassword < ApplicationRecord
  after_initialize :set_expiry!

  private

  def set_expiry!
    self.expiry(expiry: Time.zone.now).advance(hours: ENV['VALIDITY_PERIOD'].to_i)
  end
end

Or with Rails 5:

class ForgotPassword < ApplicationRecord
  attribute :expiry, :datetime, 
    ->{ Time.zone.now.advance(hours: ENV['VALIDITY_PERIOD'].to_i) }
end

You can test it by:

describe ForgotPassword do
  let(:forgot_password){ described_class.new }
  it "has a default expiry" do
    expect(forgot_password.expiry > Time.now).to be_truthy
  end
end
Sign up to request clarification or add additional context in comments.

Comments

0

You can test against described_class directly: require 'rails_helper'

describe ForgotPassword do
  context 'with forgot_password class' do
    subject { described_class }

    it { is_expected.to eq ForgotPassword }
  end
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.