2010-10-06 7 views
4

je un objettester une relation has_one?

class User < ActiveRecord::Base 
    has_one :subscription 
end 

et j'ai ce test:

it "should increment shipped count when item_shipped" do 
    @user.attributes = @valid_attributes 
    @user.save 

    subscription = mock_model(Subscription) 
    subscription.stub!(:item_shipped!) 
    subscription.stub!(:user_id) 
    @user.subscription = subscription 

    lambda{@user.item_shipped!}.should change{@user.shipped_count}.by(1) 
    end 

Mais je reçois une erreur:

1) 
Spec::Mocks::MockExpectationError in 'User should increment shipped count when item_shipped' 
Mock "Subscription_1113" received unexpected message :[]= with ("user_id", 922717357) 
./spec/models/user_spec.rb:29: 

Je ne suis pas sûr de savoir comment se moquer de cela et Je n'arrive pas à trouver de références à ce genre de chose.

Répondre

2

Au lieu de se moquant d'abonnement, essayez les méthodes stubbing sur un abonnement à la place réelle:

subscription = Subscription.new 
subscription.stub!(:item_shipped!) 
subscription.stub!(:user_id) 
@user.subscription = subscription 

Mocks peut être fragile. Tout appel à un simulacre doit être anticipé et déclaré comme une attente. Il ne semble pas que ce test particulier ait besoin de se moquer de ce modèle dans tous les cas.

EDIT: N'oubliez pas de déclarer les valeurs de retour dont dépend la classe appelante. Dans votre cas, cela pourrait ressembler:

subscription.stub!(:item_shipped!).and_return(true) 
subscription.stub!(:user_id).and_return(@user.id) 

etc.

Encore une fois, si vous n'êtes pas affirmer qu'une méthode sur votre modèle moquée devrait être appelé, alors la seule chose que moqueur ici n'est que votre test cassant. Mocks sont destinés à des choses comme:

subscription.should_receive(:some_method).once 

Sinon, il vous suffit de bouchonner les méthodes qui ont des effets secondaires indésirables qui ne concernent pas vos spécifications.

+0

Merci de ... qui ne semble pas fonctionner , mais cela pourrait être dû au fonctionnement interne de item_shipped! J'ai besoin de me moquer de l'abonnement parce qu'il est appelé à partir de la méthode que je suis en train de tester. – phil

+1

Oui, c'est difficile à dire sans connaître les détails de la méthode. Gardez à l'esprit que les simulacres sont destinés à être utilisés pour créer des attentes spécifiques. En d'autres termes, si votre spécification ne va pas affirmer qu'une certaine méthode sur un objet mocké sera appelée, il n'est pas nécessaire de se moquer de cet objet. Remplissez simplement toutes les méthodes sur une instance réelle de l'objet qui invoquerait des opérations lourdes ou autrement inédites/non désirées. Comme le fait remarquer Martin Fowler, les mocks ne sont pas des stubs: http://martinfowler.com/articles/mocksArentStubs.html –

+0

Gardez également à l'esprit que si l'utilisateur attend une valeur de retour de l'abonnement dans les composants internes de l'utilisateur # item_shipped !, vous ' ll faut définir la valeur de retour sur la méthode stubbed (voir edit). –

0

Mise en place d'associations pour les tests est facilitée avec factories: (non testé)

Factory.define :subscriber, :class => User do |f| 
    f.name "Moe Howard" 
    f.association :subscription, :factory => :subscription 
end 

Factory.define :subscription, :class => Subscription do |f| 
end 

it "should increment shipped count when item_shipped" do 
    @user = Factory.create(:subscriber) 
    lambda{@user.item_shipped!}.should change{@user.shipped_count}.by(1) 
end 

Bien sûr, vous n'êtes pas vraiment tester l'association ici - vous testez la méthode item_shipped, qui est ce que vous voulais vraiment.

+0

Intéressant, je vais essayer cela. L'utilisateur item_shipped! méthode appelle l'abonnement (parmi d'autres choses), c'est pourquoi je dois me moquer. – phil

0

changement: mock_model(Subscription)-mock_model(Subscription).as_null_object

qui permettra des messages à envoyer à l'objet (en supposant que cela est un comportement acceptable dans votre cas)

Questions connexes