2010-10-20 12 views
4

Voici un modèle que j'utilise, j'ai simplifié un peu jusqu'à la forme la plus simple qui ne fonctionne toujours pas mon exemple:Test d'une spécification de modèle qui utilise un rappel after_create

class User < ActiveRecord::Base 
    after_create :setup_lists 

    def setup_lists 
    List.create(:user_id => self.id, :name => "current") 
    List.create(:user_id => self.id, :name => "master") 
    end 
end 

Et je souhaitez spec l'exemple comme suit:

require 'spec_helper' 

describe User do 
    before(:each) do 
    @user = Factory(:user) 
    end 

    describe "#setup_lists" do 
    before(:each) do 
    List.stub(:create).with(:name => "current") 
    List.stub(:create).with(:name => "master") 

    it "creates a new master list" do 
     List.should_receive(:create).with(:name => "master") 
    end 

    it "creates a new current list" do 
     List.should_receive(:create).with(:name => "current") 
    end 
    end 
end 

Ce que je pensais ne fonctionnerait très bien, mais je suis resté avec l'erreur suivante:

Failures: 
    1) User#setup_lists creates a new master list 
    Failure/Error: List.should_receive(:create).with(:name => "current") 
    (<List(id: integer, name: string, created_at: datetime, updated_at: datetime, user_id: integer) (class)>).create({:name=>"current"}) 
     expected: 1 time 
     received: 0 times 
    # ./spec/models/user_spec.rb:44 

    2) User#setup_lists creates a new current list 
    Failure/Error: List.should_receive(:create).with(:name => "master") 
    (<List(id: integer, name: string, created_at: datetime, updated_at: datetime,  user_id: integer) (class)>).create({:name=>"master"}) 
    expected: 1 time 
    received: 0 times 
    # ./spec/models/user_spec.rb:48 

Quelqu'un peut-il m'aider à comprendre pourquoi cela se passe?

Répondre

4

Trois questions:

1) L'objet utilisateur est créé avant de l'attente du message, si should_receive ne fait jamais voir le message;

2) Vous utilisez des méthodes de remplacement pour lesquelles vous définissez également des attentes. Vous voulez bouchonner les méthodes pour lesquelles vous ne pas attentes fixées, mais qui sont nécessaires pour faire passer le test

3) Vous devez passer tous les paramètres

Pour corriger, créer l'utilisateur objet après avoir réglé le expectaion et bouchonner chaque méthode à son tour (parce que votre modèle appelle List.create deux fois):

describe User do 
    describe "#setup_lists" do 
    it "creates a new master list" do 
     List.stub(:create).with(:user_id=>1,:name => "current") 
     List.should_receive(:create).with(:user_id=>1,:name => "master") 
     @user = User.create 
    end 

    it "creates a new current list" do 
     List.stub(:create).with(:user_id=>1,:name => "master") 
     List.should_receive(:create).with(:user_id=>1,:name => "current") 
     @user = User.create 
    end 
    end 
end 

Bien qu'il soit vraiment une question de style, il est plus logique d'utiliser un objet réel de l'utilisateur ici plutôt qu'une usine, puisque vous testez le modèle lui-même.

2

La réponse de zetetic est géniale, mais si vous voulez quelque chose d'un peu plus rapide (et qui fonctionne toujours), je vous recommande d'utiliser le shoulda-callback-matchers gem. C'est un ensemble complet de coupleurs qui facilitent le test des rappels. Je suis tout à propos facile & réduisant la plaque chauffante. Vous pouvez voir quelques exemples dans mon RSpec model testing skeleton si vous voulez regarder.

Dans les deux cas, le travail est fait!