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:
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
                To run a single Rspec test file, you can do: rspec spec/models/your_spec. rb to run the tests in the your_spec. rb file.
RSpec is a unit test framework for the Ruby programming language. RSpec is different than traditional xUnit frameworks like JUnit because RSpec is a Behavior driven development tool. What this means is that, tests written in RSpec focus on the "behavior" of an application being tested.
I use the database_cleaner gem to scrub my test database before each test runs, ensuring a clean slate and stable baseline every time. By default, RSpec will actually do this for you, running every test with a database transaction and then rolling back that transaction after it finishes.
Add an .and_call_original to your message expectation:
expect(Settings).to receive(:where).with({ environment: 'test' }).once.and_call_original
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With