2010-09-01 5 views
35

Ich bin neu in Mock-Objekten, und ich versuche zu lernen, wie man sie in RSpec verwendet. Kann jemand bitte ein Beispiel (ein Hallo RSpec Mock-Objekt Welttyp Beispiel) oder einen Link (oder eine andere Referenz) zur Verwendung der RSpec-Mock-Objekt-API posten?RSpec Mock Object Beispiel

Antwort

62

Hier ist ein Beispiel für eine einfache mock ich für einen Controller-Test in einer Rails-Anwendung haben:

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 

In diesem Fall bin ich spöttisch die Seite & Pagetype-Modelle (Objekte) sowie Anstoßen aus ein paar der Methoden, die ich anrufe.

Das mir die Möglichkeit gibt, einen Test wie dies auszuführen:

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

Ich weiß, diese Antwort mehr Schienen spezifisch ist, aber ich hoffe, es hilft Ihnen heraus ein wenig.


bearbeiten

Ok, hier so ein Hallo Welt Beispiel ...

mit dem folgenden Skript (hello.rb):

class Hello 
    def say 
    "hello world" 
    end 
end 

Wir schaffen können die folgende Spezifikation (hallo_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

Dank für das Beispiel, es deff. half – agentbanks217

+11

Sie erstellen ein Mock-Objekt der Klasse, die Sie spekulieren/testen sollen, was bedeutet, dass Sie die Klasse, die überhaupt entwickelt wird, nicht ausüben. Zwecklos. Mocking soll Ihnen helfen, die getestete Klasse/System mit Objekten zu umgeben, die sich glaubwürdig als reale Welt darstellen, wenn auch einfacher/kontrolliert/in sich abgeschlossen. Es ist ein Anti-Pattern, um Mocking zu verwenden, um interne Funktionen der entwickelten Klasse zu überprüfen. –

+0

Diese Antwort ist nicht mehr aktuell. Siehe [tokhis Antwort unten] (https://stackoverflow.com/a/39573538/634576) für das Schreiben eines reinen Mock-Objekts und [meine] (https://Stackoverflow.com/a/39186152/634576) für wie im aktuellen RSpec teilweise verspotten. –

5

Ich habe nicht genug Punkte, um einen Kommentar zu einer Antwort zu posten, aber ich wollte sagen, dass die akzeptierte Antwort mir auch dabei half herauszufinden, wie man einen zufälligen Wert eingibt.

Ich musste in der Lage sein, eine Objektinstanzwert Stummel, die zufällig zum Beispiel zugeordnet:

class ClumsyPlayer < Player do 

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

Da ist in meinem spec ich herauszufinden, hatte ein Problem, wie die ungeschickte Spielers zufällige Gesundheit Stummel zu testen Wenn sie eine Heilung bekommen, bekommen sie den richtigen Schub für ihre Gesundheit.

Der Trick war:

@player.stub!(health_boost: 5) 

Damit stub! war der Schlüssel, ich hatte stub gerade mit und wurde noch zufällig rspec Pässe und Ausfälle bekommen.

Also danke Brian

0

Strom (3.x) RSpec bietet sowohl reine Mock-Objekte (wie in tokhi's answer) und teilweise spöttisch (Anrufe auf ein vorhandenes Objekt spöttisch). Hier ist ein Beispiel für eine teilweise Verspottung. Es verwendet expect und receive, um einen Order Aufruf an eine CreditCardService zu verspotten, so dass der Test nur besteht, wenn der Anruf getätigt wird, ohne es tatsächlich zu machen.

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 

In diesem Beispiel ist die mock auf dem Rückgabewert von CreditCardService.instance ist, die vermutlich ein Singleton ist.

with ist optional; ohne sie würde jeder Anruf zu refund die Erwartung erfüllen. Ein Rückgabewert könnte mit and_return gegeben werden; In diesem Beispiel wird es nicht verwendet, daher gibt der Aufruf nil zurück.


In diesem Beispiel wird RSpec aktuelle (expect .to receive) spöttische Syntax, die mit einem Objekt arbeitet. Die akzeptierte Antwort verwendet die alte Methode rspec-rails mock_model, die für ActiveModel-Modelle spezifisch war und aus rspec-rails in ein anderes Juwel verschoben wurde.

4

mock ist basierend auf diesem Github pull veraltet.

Anstatt nun können wir double verwenden - mehr 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