2010-09-01 5 views
35

Je suis nouveau à simuler des objets, et j'essaie d'apprendre à les utiliser dans RSpec. Quelqu'un peut-il s'il vous plaît poster un exemple (un bon exemple de type monde objet RSpec Mock), ou un lien (ou toute autre référence) sur la façon d'utiliser l'API RSpec mock object?RSpec Mock Exemple d'objet

Répondre

62

Voici un exemple simple maquette, je l'ai fait pour un test de contrôleur dans une application rails:

before(:each) do 
    @page = mock_model(Page) 
    @page.stub!(:path) 
    @page.stub!(:find_by_id) 
    @page_type = mock_model(PageType) 
    @page_type.stub!(:name) 
    @page.stub!(:page_type).and_return(@page_type) 
end 

Dans ce cas, je suis moqueur la page & modèles pageType (objets), ainsi que stubbing sur quelques-unes des méthodes que j'appelle.

Cela me donne la possibilité d'exécuter un des tests comme celui-ci:

it "should be successful" do 
    Page.should_receive(:find_by_id).and_return(@page) 
    get 'show', :id => 1 
    response.should be_success 
end 

Je sais cette réponse est plus spécifique rails, mais j'espère que cela vous aide un peu.


Modifier

Ok, alors voici un exemple du monde bonjour ...

Compte tenu du script (bonjour.rb) suivant:

class Hello 
    def say 
    "hello world" 
    end 
end 

Nous pouvons créer la spécification suivante (hello_spec.rb):

require 'rubygems' 
require 'spec' 

require File.dirname(__FILE__) + '/hello.rb' 

describe Hello do 
    context "saying hello" do 
    before(:each) do 
     @hello = mock(Hello) 
     @hello.stub!(:say).and_return("hello world") 
    end 

    it "#say should return hello world" do 
     @hello.should_receive(:say).and_return("hello world") 
     answer = @hello.say 
     answer.should match("hello world") 
    end 
    end 
end 
+0

merci pour l'exemple, il deff. aidé – agentbanks217

+11

Vous êtes en train de configurer un objet simulé de la classe que vous êtes censé tester/tester, ce qui signifie que vous n'exercez pas du tout la classe en cours de développement. Inutile. Le simulacre est conçu pour vous aider à entourer la classe/le système testé avec des objets se présentant de manière crédible comme un environnement réel bien que plus simple/contrôlé/autonome. C'est un anti-pattern d'utiliser Mocking pour vérifier le fonctionnement interne de la classe en cours de développement. –

+0

En outre, cette réponse est périmée. Voir [la réponse de tokhi ci-dessous] (https://stackoverflow.com/a/39573538/634576) pour savoir comment écrire un pur objet maquette et [mine] (https://stackoverflow.com/a/39186152/634576) pour savoir comment faire des moqueries partielles dans RSpec actuel. –

5

Je n'ai pas assez de points pour poster un commentaire à une réponse mais je voulais dire que la réponse acceptée m'a aussi aidé à essayer de comprendre comment faire un bout dans une valeur aléatoire.

je devais être en mesure de la valeur stub d'instance d'un objet qui est assigné au hasard par exemple:

class ClumsyPlayer < Player do 

    def initialize(name, health = 100) 
    super(name, health) 
    @health_boost = rand(1..10) 
    end 
end 

Puis dans mon spec j'avais un problème sur trouver comment stub santé aléatoire du joueur maladroit à tester quand ils obtiennent une guérison, ils obtiennent le coup de pouce approprié à leur santé.

L'astuce était:

@player.stub!(health_boost: 5) 

Alors que stub! était la clé, j'avais juste en utilisant stub et était encore en train de passes et les échecs rspec aléatoires.

Je vous remercie Brian

0

actuel (3.x) RSpec fournit à la fois purs objets fantaisie (comme dans tokhi's answer) et un mock partiel (se moquant des appels à un objet existant). Voici un exemple de moquerie partielle. Il utilise expect et receive pour simuler un appel Order à un CreditCardService, de sorte que le test ne passe que si l'appel est effectué sans avoir à le faire réellement.

class Order 
    def cancel 
    CreditCardService.instance.refund transaction_id 
    end 
end 

describe Order do 
    describe '#cancel' do 
    it "refunds the money" do 
     order = Order.new 
     order.transaction_id = "transaction_id" 
     expect(CreditCardService.instance).to receive(:refund).with("transaction_id") 
     order.cancel 
    end 
    end 
end 

Dans cet exemple, la maquette est sur la valeur de retour de CreditCardService.instance, qui est sans doute un singleton.

with est optionnel; sans cela, tout appel à refund satisferait les attentes. Une valeur de retour peut être donnée avec and_return; dans cet exemple, il n'est pas utilisé, l'appel renvoie donc nil.


Cet exemple utilise le courant (expect .to receive) syntaxe se moquant de RSpec, qui fonctionne avec un objet. La réponse acceptée utilise l'ancienne méthode rspec-rails mock_model, qui était spécifique aux modèles ActiveModel et qui a été déplacée de rspec-rails vers une autre gemme.

4

mock est dépréciée sur la base de ce github pull.

Maintenant, au lieu que nous pouvons utiliser double - plus here...

before(:each) do 
    @page = double("Page") 
    end 

    it "page should return hello world" do 
    allow(@page).to receive(:say).and_return("hello world") 
    answer = @page.say 
    expect(answer).to eq("hello world") 
    end