Заглушка связанных методов с помощью Rspec

Я хочу вызвать named_scope, который будет возвращать только одну запись, но named_scope возвращает массив, это не имеет большого значения, так как я могу просто связать его с .first:

Model.named_scope(param).first

и это работает, с чем я борюсь, так это как заглушить связанный вызов. У кого-нибудь есть ссылка или ответ о том, как я могу добиться этого с насмешкой Rspec?


person nitecoder    schedule 20.03.2009    source источник


Ответы (5)


Я кое-что понял.

Client.stub!(:named_scope).and_return(@clients = mock([Client]))
@clients.stub!(:first).and_return(@client = mock(Client))

что позволяет мне вызывать мой контроллер:

@client = Client.named_scope(param).first

Это работает, но есть ли лучшее решение?

РЕДАКТИРОВАТЬ:

Выпуск rspec 1.2.6 позволяет нам использовать stub_chain, что означает, что теперь это может быть:

Client.stub_chain(:named_scope, :chained_call).and_return(@clients = [mock(Client)])

Это было в моей голове, как всегда, проверяйте API на предмет специфики :)

person nitecoder    schedule 20.03.2009
comment
Возможно, переместите раздел EDIT: в начало ответа. - person Sam; 07.01.2011
comment
Большое спасибо, Крис! Очень помогло!! - person Nikita Fedyashev; 23.01.2011

Лучшая версия

Client.stub!(:named_scope).and_return(@clients = mock([Client]))
@clients.stub!(:first).and_return(@client = mock(Client))

будет:

Client.should_receive(:named_scope).with(param).and_return do
  record = mock_model(Comm)
  record.should_receive(:do_something_else)
  [record]  
end
person luacassus    schedule 06.07.2011

Вопрос довольно старый, и поэтому есть несколько улучшений в том, как можно сделать заглушку. Теперь вы можете использовать метод stub_chain, чтобы заглушить цепочку вызовов методов. Например:

@client = Client.named_scope(param).first

можно заглушить с помощью:

Client.stub_chain(:named_scope,:first).and_return(@client = mock(Client))

Еще примеры stub_chaining:

describe "stubbing a chain of methods" do
  subject { Object.new }

  context "given symbols representing methods" do
    it "returns the correct value" do
      subject.stub_chain(:one, :two, :three).and_return(:four)
      subject.one.two.three.should eq(:four)
    end
  end

  context "given a string of methods separated by dots" do
    it "returns the correct value" do
      subject.stub_chain("one.two.three").and_return(:four)
      subject.one.two.three.should eq(:four)
    end
  end
end

или взгляните на:

Да здравствует rspec!!! :)

person Sahil Dhankhar    schedule 10.07.2013

Я полагаю, это в спецификации контроллера?

Ваше собственное предложение должно работать нормально. Другая возможность — переместить вызов named_scope внутрь вашей модели, чтобы полностью избежать проблемы. Это также соответствует совету «толстые модели, тонкие контроллеры».

person Antti Tarvainen    schedule 20.03.2009

Я думаю, что вы уже сделали тонкий контроллер, поместив запрос в именованную область, где его можно использовать повторно. Вот некоторый код, который я использовал до того, как начал использовать именованные области.

  def mock_comm(stubs={})
    @mock_comm ||= mock_model(Comm, stubs)
  end

  describe "responding to GET index" do

    it "should expose all comms as @comms" do
      Comm.should_receive(:find).with(:all).and_return([mock_comm])
      get :index
      assigns[:comms].should == [mock_comm]
    end
# ...

Я бы, вероятно, написал код, очень похожий на тот, что у вас уже есть, но, возможно, поместил бы его в помощник, который позволил бы мне повторно использовать его. Другое дело — использовать другой макетный фреймворк, который, возможно, даст вам больше контроля. Взгляните на railscast Райана Бейтса на RSpec — он уже немного устарел, но все еще содержит несколько хороших идей.

person Ghoti    schedule 20.03.2009