Заглушение Цепочечных методов с помощью Rspec
-
21-08-2019 - |
Вопрос
Я хочу вызвать named_scope, который вернет только одну запись, но named_scope возвращает массив, это не имеет большого значения, поскольку я могу просто связать его с .first:
Model.named_scope(param).first
и это работает, с чем я борюсь, так это с тем, как заглушить связанный вызов.У кого-нибудь есть ссылка или ответ о том, как я мог бы добиться этого с помощью Rspec mocking?
Решение
Я кое-что выяснил.
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 на предмет специфики :)
Другие советы
Лучшая версия
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
Вопрос довольно старый, и, следовательно, есть несколько улучшений в том, как можно выполнить заглушку.Теперь вы можете использовать метод 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!!!:)
Я полагаю, это есть в спецификации контроллера?
Ваше собственное предложение должно сработать нормально.Другая возможность заключается в перемещении вызова named_scope внутри вашей модели, чтобы полностью избежать проблемы.Это также соответствовало бы совету "толстые модели, тонкие контроллеры".
Я думаю, вы уже сделали с тонким контроллером, поместив запрос в именованную область, где его можно использовать повторно.Вот некоторый код, который я использовал до того, как начал использовать именованные области.
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 - он уже немного устарел, но в нем все еще есть несколько хороших идей.