简体   繁体   中英

How can I test memoization with RSpec?

I have the next code in one of my classes:

class Settings < ActiveRecord::Base
  def self.current
    @settings ||= Settings.where({ environment: Rails.env }).first_or_create!
  end
  # Other methods
end

Basic behaviour:

  1. It creates a new record on first call.
  2. It returns the same result with subsequent calls.
  3. It resets the ivar after each update, returning the first (and unique) record associated to current environment in subsequent calls.

For this method I have the next test:

describe Settings do
  describe ".current" do
    it "gets all settings for current environment" do
      expect(Settings.current).to eq(Settings.where({ environment: 'test' }).first)
    end
  end
end

I don't feel comfortable with that because I'm actually not testing memoization, so I have been following the approach on this question , and I have tried something like that:

describe ".current" do
  it "gets all settings for current environment" do
    expect(Settings).to receive(:where).with({ environment: 'test' }).once
    2.times { Settings.current }
  end
end

But this test returns the following error:

NoMethodError:
  undefined method `first_or_create!' for nil:NilClass

So my question is, how can I test memoization on this method with RSpec?

UPDATE:

Finally, my approach is as follows:

describe Settings do
  describe ".current" do
    it "gets all settings for current environment" do
      expect(described_class.current).to eq(described_class.where(environment: 'test').first)
    end
    it "memoizes the settings for current environment in subsequent calls" do
      expect(described_class).to receive(:where).once.with(environment: 'test').and_call_original
      2.times { described_class.current }
    end
  end
end

在您的邮件期望中添加.and_call_original

expect(Settings).to receive(:where).with({ environment: 'test' }).once.and_call_original

The code below calls Settings.current twice and checks if they are both equal to each other to check if the value has been memoized. We also stub out all other methods that we aren't testing.

describe ".current" do
  it "gets all settings for current environment" do
    relation = double("relation")
    expect(relation).to receive(:first_or_create!).once
    expect(Settings).to receive(:where).with({ environment: 'test' }).once.and_return(relation)
    settings = Settings.current
    expect(Settings.current).to eq settings
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM