Сцепление цепочечных методов с помощью Rspec - PullRequest
11 голосов
/ 20 марта 2009

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

Model.named_scope(param).first

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

Ответы [ 5 ]

16 голосов
/ 20 марта 2009

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

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

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

@client = Client.named_scope(param).first

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

EDIT:

Релиз rspec 1.2.6 позволяет нам использовать stub_chain, то есть теперь он может быть:

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

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

2 голосов
/ 10 июля 2013

Вопрос довольно старый, и поэтому есть немного улучшений в том, как можно делать заглушки Теперь вы можете использовать метод 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

или, пожалуйста, посмотрите:

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

2 голосов
/ 06 июля 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
1 голос
/ 20 марта 2009

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

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

0 голосов
/ 20 марта 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 - сейчас он немного устарел, но у него все еще есть хорошие идеи.

...