2009-03-20 18 views
11

Ich möchte ein named_scope aufzurufen, die nur einen Datensatz zurück, aber die named_scope gibt ein Array, das ist keine große Sache, wie ich gerade Kette kann es mit .First:Stubbing Chained Methoden mit Rspec

Model.named_scope(param).first 

und das funktioniert, womit ich mich abmühen muss ist, wie man den angeketteten Anruf stumm macht. Hat jemand eine Referenz oder eine Antwort darauf, wie ich das mit Rspec-Mocking erreichen würde?

Antwort

16

Ich habe etwas herausgefunden.

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

, die mir mein Controller aufrufen können:

@client = Client.named_scope(param).first 

Es funktioniert, aber ist es eine bessere Lösung?

EDIT:

Die Freisetzung von rspec 1.2.6 ermöglicht es uns, stub_chain zu nutzen bedeutet, dass es jetzt sein kann:

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

Das war Spitze von meinem Kopf, wie immer die api für Einzelheiten überprüfen:)

+2

Vielleicht verschieben Sie die EDIT: Abschnitt an die Spitze der Antwort – Sam

+0

Vielen Dank, Chris! Es hat sehr geholfen !! – ep3static

1

Ich nehme an, das ist in einer Controller-Spezifikation?

Ihr eigener Vorschlag sollte gut funktionieren. Eine andere Möglichkeit besteht darin, den Aufruf named_scope in Ihr Modell zu verschieben, um das Problem vollständig zu vermeiden. Dies würde auch im Einklang mit den Ratschlägen "Fette Modelle, dünne Steuerungen" stehen.

0

Ich denke, Sie haben die Thin-Controller-Sache bereits getan, indem Sie die Abfrage in einen benannten Bereich, wo es wiederverwendet werden kann. Hier ist ein Code, den ich verwendet habe, bevor ich mit der Verwendung von benannten Bereichen begonnen habe.

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 
# ... 

Ich würde wahrscheinlich Code ganz ähnlich schreiben, was Sie bereits, aber es vielleicht in einem Helfer setzen, dass ich es wieder verwenden kann. Die andere Sache ist, einen anderen spöttischen Rahmen zu verwenden, der Ihnen vielleicht mehr Kontrolle gibt. Schaut euch den Railscast von Ryan Bates auf RSpec an - er ist jetzt ein bisschen alt, aber noch ein paar gute Ideen drin.

2

bessere Version von

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

wird:

Client.should_receive(:named_scope).with(param).and_return do 
    record = mock_model(Comm) 
    record.should_receive(:do_something_else) 
    [record] 
end 
2

Die Frage ist ziemlich alt und daher gibt es einige Verbesserungen, wie Anstoßen getan werden kann. Jetzt können Sie die Methode stub_chain verwenden, um eine Kette von Methodenaufrufen zu stubben. Zum Beispiel:

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

Weitere Beispiele für 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 

or please have a look at:

@client = Client.named_scope(param).first

mit rodenEs lebe die rspecs !!! :)