2015-09-02 11 views
6

sto testando il mio modulo e ho deciso di provarlo contro classe anonima:Stub metodo non implementato in rspec

subject(:klass) { Class.new { include MyModule } } 

MyModule utilizza il metodo name all'interno klass. Per far funzionare le mie specifiche ho bisogno di stub questo metodo name (che non è implementato). Così ho scritto:

subject { klass.new } 
allow(subject).to receive(:name).and_return('SOreadytohelp') } 

ma solleva:

RSpec::Mocks::MockExpectationError: #<#<Class:0x007feb67a17750>:0x007feb67c7adf8> does not implement: name 
from spec-support-3.3.0/lib/rspec/support.rb:86:in `block in <module:Support>' 

come stub questo metodo senza definirlo?

+0

Non so se è la risposta ma si ha un errore di battitura; 'subjet {klass.new}'. Non dovrebbe essere: 'subject {klass.new}' (manca una 'c'). Prova questo e facci sapere! –

risposta

3

RSpec solleva questa eccezione perché non è utile stub un metodo che non esiste sull'oggetto originale.

I metodi di simulazione sono sempre soggetti a errori perché il mock potrebbe comportarsi in modo diverso rispetto all'implementazione originale e pertanto le specifiche potrebbero essere valide anche se l'implementazione originale avrebbe restituito un errore (o non esiste nemmeno). Consentire di simulare metodi inesistenti è semplicemente sbagliato.

Pertanto vorrei sostenere che non si dovrebbe cercare di aggirare questa eccezione. Basta aggiungere un metodo name alla classe che solleva un'eccezione chiaro se eseguire al di fuori dell'ambiente di prova:

def self.name 
    raise NotImplementedError # TODO: check specs... 
end 
+0

'name' dovrebbe probabilmente essere un metodo di istanza che restituisce' 'SOreadytohelp'' – Stefan

+0

@Stefan: Sono d'accordo, anche questa è una buona idea. Dipende dall'attenzione: sottolineare che le specifiche e il codice sono sincronizzati o che c'è qualcosa da sistemare ... – spickermann

1

Penso che se il test si sta scrivendo è focalizzata sul modulo MyModule, e che il modulo si basa su un metodo di istanza nella classe in cui è stato mescolato, quindi penso che il metodo dovrebbe essere preso in giro nella classe anonima che si usa durante il test del modulo. Ad esempio:

module MyModule 
    def call_name 
    # expected implementation of #name to be 
    # in the class this module is mixed into 
    name 
    end 
end 

RSpec.describe MyModule do 
    let(:my_module_able) do 
    Class.new do 
     include MyModule 

     # We don't care what the return value of this method is; 
     # we just need this anonymous class to respond to #name 
     def name 
     'Some Name that is not SOReadytohelp' 
     end 
    end.new 
    end 

    describe '#call_name' do 
    let(:name) { 'SOReadytohelp' } 

    before do 
     allow(my_module_able).to receive(:name).and_return(name) 
    end 

    it 'returns the name' do 
     expect(my_module_able.call_name).to eq(name) 
    end 
    end 
end 
Problemi correlati