2009-03-20 17 views
11

Je veux appeler un named_scope qui ne renverra un enregistrement, mais le named_scope retourne un tableau, ce n'est pas une grosse affaire que je peux enchaîner avec .first:Stubbing Chained Méthodes avec Rspec

Model.named_scope(param).first 

et cela fonctionne, ce que je suis aux prises avec est comment couper l'appel chaîné. Est-ce que quelqu'un a une référence ou une réponse sur la façon dont je m'y prendrais avec Rspec moqueur?

Répondre

16

J'ai trouvé quelque chose.

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

qui me permet d'appeler mon contrôleur:

@client = Client.named_scope(param).first 

Il fonctionne, mais est-il une meilleure solution?

EDIT:

La libération de rspec 1.2.6 nous permet d'utiliser stub_chain ce qui signifie qu'il peut désormais:

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

C'était haut de ma tête, comme toujours vérifier le api pour plus de détails:)

+2

Peut-être déplacer la section EDIT: vers le haut de la réponse – Sam

+0

Merci beaucoup, Chris! Cela a beaucoup aidé !! – ep3static

1

Je suppose que c'est dans une spécification de contrôleur?

Votre propre suggestion devrait fonctionner correctement. Une autre possibilité consiste à déplacer l'appel named_scope à l'intérieur de votre modèle, pour éviter complètement le problème. Ce serait également en accord avec le conseil "gros modèles, contrôleurs minces".

0

Je pense que vous avez déjà fait la chose du contrôleur mince en plaçant la requête dans une portée nommée où elle peut être réutilisée. Voici du code que j'ai utilisé avant de commencer à utiliser des étendues nommées.

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

je ne serais probablement écrire un code assez similaire à ce que vous avez déjà, mais peut-être mis dans une aide qui me permet de le réutiliser. L'autre chose est d'utiliser un autre cadre de simulation qui vous donne peut-être plus de contrôle. Jetez un coup d'œil à Railcast de Ryan Bates sur RSpec - c'est un peu vieux maintenant mais il y a quand même quelques bonnes idées là-dedans.

2

Une meilleure version de

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

sera:

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

La question est assez vieux et donc il y a quelques améliorations dans la façon dont stubbing peut être fait. Vous pouvez maintenant utiliser la méthode stub_chain pour remplacer une chaîne d'appels de méthode. Par exemple:

@client = Client.named_scope(param).first

peut être bouchonné avec:

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

Plus exemples de 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:

Vive les rspecs !!! :)