Blankman
Blankman

Reputation: 267020

How to mock database calls with RSpec

I am trying to test a JSON API endpoint and I am getting an ActiveRecord::RecordNotFound exception because the call to user.find is failing.

How can I mock the active record calls for my test so that it return something and doesn't throw an exception?

(I am using factory_girl also, in case I can use that)

def do_something
  success = false
  message = ""

  user = User.find(params[:user_id])

  if user.present?
    # ...

    if user.save!
      success = true
    end
  end

  render json: {
    "success": success,
    "message": message
  }
end

My RSpec looks like:

#RSpec.describe Api::UsersController, type: :controller do 

it "should return some JSON" do 
  payload = {
    user_id: "1",
    # ...
  }.to_json

  post :do_something, payload, format: :json

  expected = {
    success: false,
    message: ""
  }.to_json 

  expect(response.body).to eq(expected)
end

Upvotes: 1

Views: 8111

Answers (2)

Thanh
Thanh

Reputation: 8604

I think you need to create a user first by using FactoryGirl, then you can pass id of that user in payload, like this:

let(:user) { create :user } # create user by FactoryGirl

it "should return some JSON" do
  payload = {
    user_id: user.id,
    # ...
  }.to_json
  ...
end

Upvotes: 1

Sinscary
Sinscary

Reputation: 692

Well in case you want to mock database with ActiveRecord, you can try something like this.

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

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

  def create_table
    ActiveRecord::Base.connection.create_table :mock_table do |t|
      t.integer :user_id
      t.timestamps
    end
  end

  def drop_table
    ActiveRecord::Base.connection.drop_table :mock_table
  end

But you have to establish connection before you proceed and you can put your connection adapter in spec_helper

ActiveRecord::Base.establish_connection(
  adapter:  'sqlite3',
  database: ':memory:'
)

You can change your column names with whatever you want and also this will create table when spec is run and will destroy once spec is passed.

Note: Don't forget to require active_record and sqlite3 in your spec_helper or wherever you want to use.

Hope it helps.

Upvotes: 1

Related Questions