2013-12-18 4 views
4

У меня есть следующий код в одном из моих классов:Как я могу проверить memoization с RSpec?

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

Basic поведения:

  1. Это создает новый рекорд по первому зову.
  2. Он возвращает тот же результат с последующими вызовами.
  3. Сбрасывает ivar после каждого обновления, возвращая первую (и уникальную) запись, связанную с текущей средой, в последующих вызовах.

Для этого метода у меня есть следующий тест:

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 

Я не чувствую себя комфортно с этим, потому что я на самом деле не испытывая запоминанием, поэтому я был в соответствии с подходом на this question и Я пытался что-то вроде этого:

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 

Но этот тест возвращает следующее сообщение об ошибке:

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

Так что мой вопрос: как я могу проверить memoization на этот метод с RSpec?

UPDATE:

Наконец, мой подход заключается в следующем:

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 
+1

нет необходимости проверять меморандум – NARKOZ

+1

Почему я не должен проверять меморандум? – backpackerhh

ответ

7

Добавить .and_call_original к сообщению ожидания:

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

Спасибо! Отлично работает. Я не знал о '.and_call_original'. – backpackerhh

+0

Вы также можете просто вернуть объект-заглушку с помощью '.and_return (stub)'. До тех пор, пока вы что-то заглушите, второй вызов вернет кешированный результат. – cassianoleal

0

ниже код вызывает Settings.current дважды и проверяет, равны ли они равным ea ch other, чтобы проверить, сохранено ли значение. Мы также исчерпываем все другие методы, которые мы не тестируем.

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 
Смежные вопросы