2012-06-01 4 views
32

Esiste un metodo per rimuovere qualsiasi stub e mocking durante l'uso di RSpec?In RSpec, esiste un metodo equivalente a "unstub" ma per "should_receive"?

Esempio:

RestClient.should_receive(:delete).with("http://www.example.com") 
... 
... 

# this will remove the mocking of "should_receive" and 
# restore the proper "delete" method on "RestClient". 
RestClient.mocking_reset 

(mocking_reset è il mio nome fittizio per la funzionalità richiedono).

So che esiste il metodo "nonstub" che reimposta "stub" ma non "should_receive" s.

Quindi, esiste un metodo equivalente a "unstub" ma a "should_receive"?

Panayotis

+0

È ridicolo che non è possibile effettuare una modifica di meno di 6 caratteri! Il tuo nome del metodo lì sopra dice 'mocking_resest' e dovrebbe dire' mocking_reset'. –

+0

Aggiungi un messaggio di modifica e la tua modifica supererà 6 caratteri :) – Galen

risposta

29

Al momento (rspec-mock 2.10.1) non v'è un metodo equivalente unstub ma per should_receive. Puoi reimpostare tutti gli stub e i mock usando rspec_reset, e puoi anche scrivere degli hack sporchi per rimuovere una particolare aspettativa (che non raccomanderei).

Il seguente è un esempio di rimozione di tutti i mozziconi e le aspettative su un oggetto:

describe "resetting stubs and expectations with rspec_reset" do 
    before do 
    @person = mock('person') 
    @person.should_receive(:poke) 
    end 

    it "should not fail when we reset all stubs and expectations" do 
    @person.rspec_reset 
    end 
end 

Nota che questo metodo è annotato nel codice sorgente RSpec come @private, il che significa che si dovrebbe evitare di utilizzare più di assolutamente necessario e potrebbe rompersi nelle versioni future di rspec senza preavviso. È, tuttavia, abbastanza ampiamente usato nelle specifiche per rspec stesso, quindi sembra meno probabile che questo sarà presto ritirato.

Dopo aver scavato attraverso il codice RSpec-schernisce un po 'di più, si può ovviamente fare qualcosa di veramente brutto e strappare quella aspettativa specifica te stesso:

# Works in rspec 2.10.1 
describe "removing an expectation with an ugly hack" do 
    before do 
    @person = mock('person') 
    @person.should_receive(:poke) 
    end 

    it "should not fail after we hack rspec by violating every law of good programming, ever" do 
    @person.instance_variable_get(:@mock_proxy).instance_variable_get(:@method_double)[:poke].clear 
    end 
end 

Questo è davvero male in quanto viola l'incapsulamento di il pacchetto di test rspec e non dovresti farlo. Invece, se si avesse davvero un valido motivo per rimuovere una particolare aspettativa, la cosa giusta da fare sarebbe aggiungere un metodo pubblico a monte in rspec-mocks che aggiunge un metodo parallelo a unstub ma per rimuovere specifiche aspettative. Sarebbe probabilmente essere trovate qui (si noti la definizione di stub e unstub pure in questo file):

https://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks/methods.rb

Prima di uscire e utilizzando qualsiasi dei suggerimenti di cui sopra per rimuovere l'aspettativa che si può prendere in considerazione se le tue specifiche hanno davvero bisogno di fare questo o se dovrebbero essere refactored. L'utilizzo di should_receive è un'asserzione relativa al tuo codice e, in genere, dovresti provare a creare esempi (ovvero i blocchi it) che affermano solo una cosa. Sarei molto curioso di sapere perché hai bisogno di qualcosa come rspec_reset a meno che tu non stia provando a fare troppe impostazioni globali (ad esempio before :each o precedenti: tutti i blocchi), o se i tuoi esempi stanno cercando di fare troppo (cioè con più asserzioni in un singolo esempio).

L'unica eccezione a questo può essere nella suite di test di rspec-mocks, dove rspec_reset viene utilizzato per ripristinare lo stato tra gli esempi che testano la funzionalità dell'applicazione di stub e mock. A meno che non lo stiate facendo, è probabile che i vostri test possano essere migliorati per non fare affidamento su reimpostazioni globali di stub e mock su un oggetto.

Spero che questo aiuti e per favore fatemi sapere se pensate che vi sia un motivo legittimo per aggiungere un metodo equivalente a unstub ma per le aspettative del messaggio (cioè, dopo aver usato should_receive). Se sono convinto che questa è una cosa OK da fare, prenderei in considerazione l'aggiunta di questo metodo e proponendone l'aggiunta a monte. Forse si chiamerebbe unset_expectation? Si prega inoltre di utilizzare la guida nel codice e le strutture interne di cui sopra per mettere insieme una richiesta pull per rspec-mocks da soli, e vedremo se verrà accettato di creare un equivalente di simulazione di unstub.

+1

La ringrazio molto per la tua risposta. Il motivo per cui volevo questa funzionalità era perché avevo un metodo "clean_test_data" eseguito "after: each". Ciò ha richiesto di utilizzare i metodi reali. Dopo aver postato la mia domanda su SOF, mi sono reso conto che potevo ancora usare "clean_test_data" ma su "before: each" e quella era la soluzione al mio problema. In quel modo, alla fine non ho avuto bisogno di un nonstub o di unstock. Nel frattempo, poiché in passato ho trovato buone ragioni per usare "nonstub", non vedo perché non abbia l'equivalente "unset_expectation" per ragioni di completezza e poi permetto all'utente finale di decidere. –

6

Per RSpec> = 2,14, la risposta accettata non funzionerà più. Vi rimando alla risposta di Bernhard Köhler su questo thread (riprodotto qui di seguito per la salvaguardia contro collegamento rot): undefined method `rspec_reset' with rspec version 2.14

Il metodo di reset non esiste in RSpec 2.14. Al contrario, è un metodo helper definito all'interno del file spec_helper.rb per il progetto rspec-mocks .

module VerifyAndResetHelpers 
    def verify(object) 
    RSpec::Mocks.proxy_for(object).verify 
    end 

    def reset(object) 
    RSpec::Mocks.proxy_for(object).reset 
    end 
end 

Si può vedere che questo metodo delegati l'azione di ripristino al delega sottostante invece di virare su alla definizione della classe del l'oggetto in questione.

31

È possibile sovrascrivere alcuni beffardo precedente:

expect(RestClient).to receive(:delete).and_call_original 

Oppure, se non è stato alcun tipo di aspettativa, solo un semplice stub:

allow(RestClient).to receive(:delete).and_call_original 

Ricordate esiste anche expect_any_instance_of e allow_any_instance_of.