9

I am trying to write specs for my gem, which generates otp and saves it in db. Now i am writing specs for it. so basically i have three methods generate_otp!, regenerate_otp!, verify_otp(otp). what generate_otp! does is it calls a method generate_otp which contains three variables

  1. otp_code - basically a random value generated using secure_random
  2. otp_verified - a boolean value to set the status whether otp is verified or not
  3. otp_expiry_time - sets expiry time for otp which can be set by rails app in configuration.

these all three are columns of my db also.

Now after generate_otp i am calling active_records's save method to save values to db.

Now for testing i am using in :memory: and storing values in table. after testing i am dropping the db. Now i am not getting how to stub the randomly generated value and test whether value is assigned or not to all three columns, i.e, otp_code , otp_verified, otp_expiry_time.

Here is code for my methods which i need to test.

def generate_otp
    self.otp_verified = false
    self.otp_expiry_time = OtpGenerator::configuration.otp_expiry_time 
    self.otp_code = SecureRandom.hex(4)
  end

def generate_otp!
   generate_otp
   save
end

Any help with this ? I have also checked this question, but not much helpful. It's first time i am writing specs and really don't have that much experience with rspecs. I have also studied the official documentation for mock and stub, but i am really getting confused.

update : otp_spec code

require 'spec_helper'

describe OtpGenerator do
  
  let(:user) { build_mock_class.new() }
  before(:all) { create_table }
  after(:all) { drop_table }

  describe '#generate_otp' do
    it 'generate otp and save it' do
      user.generate_otp!
      
    end
  end

  describe '#regenerate_otp' do
    it 'regenerate otp and save it' do
      
    end
  end

  describe '#verify_otp' do
    it 'verifies otp' do
      
    end
  end

  def build_mock_class
    Class.new(ActiveRecord::Base) do
      self.table_name = 'mock_table'
      include OtpGenerator
    end
  end

  def create_table
    ActiveRecord::Base.connection.create_table :mock_table do |t|
      t.string :otp_code
      t.boolean :otp_verified
      t.datetime :otp_expiry_time
    end
  end

  def drop_table
    ActiveRecord::Base.connection.drop_table :mock_table
  end
end
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Sinscary
  • 652
  • 12
  • 32
  • The linked question and answers won't make much sense if you are learning a different approach to stubbing methods. Each testing library (and versions of RSpec) has slightly different syntax for method stubs, so take care you are not mixing between examples you found on the internet. Most of the details in your question (including the fact that want to stub a method of a random number generator) are irrelevant. Could you show where you are with a single RSpec test, and what exactly you are stuck on from the documentation? Also, it is really key to pick an example behaviour you want to assert. – Neil Slater Jul 14 '16 at 09:34
  • actually that's what the problem, i am not getting how to stub and than verify that value is stored in db and assigned to otp_code column. i am getting confused here. – Sinscary Jul 14 '16 at 09:37
  • Show what you have so far, and very important to show what you want your test to demonstrate. – Neil Slater Jul 14 '16 at 09:38
  • Neil i have updated the question. now what i want is to test that value is assigned to `otp_code` column and also want to stub the generated value and make sure that this value is being saved in db. – Sinscary Jul 14 '16 at 09:42

1 Answers1

16

A direct approach to stubbing out the SecureRandom method in rspec would be as follows:

before { allow(SecureRandom).to receive(:hex).with(4).and_return('abcd1234') }

You can then check that 'abcd1234' is stored in the database. In order to keep the test DRY, you may also wish to reference this as a variable, e.g. let(:random_value) { 'abcd1234' }.

Tom Lord
  • 27,404
  • 4
  • 50
  • 77