2015-09-02 13 views
6

ich mein Modul zu testen und ich beschlossen, es im Vergleich zu anonymen Klasse zu testen:Stub unimplemented Methode in rspec

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

MyModule Methode verwendet name innerhalb klass. Um meine Spezifikationen arbeiten zu lassen, muss ich diese Methode name stubben (was nicht implementiert ist). Also schrieb ich:

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

aber es wirft:

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>' 

, wie diese Methode Stummel ohne ihn zu definieren?

+0

Ich weiß nicht, ob es die Antwort ist, aber Sie haben einen Tippfehler; 'subjet {klass.new}'. Sollte es nicht sein: 'subject {klass.new}' (fehlt ein 'c'). Probieren Sie das aus und lassen Sie es uns wissen! –

Antwort

3

RSpec hebt diese Ausnahme, weil es nicht sinnvoll ist, ein Verfahren zu Stummel, die nicht auf dem Original-Objekt existiert.

Mocking-Methoden sind immer fehleranfällig, da sich der Mock möglicherweise anders verhält als die ursprüngliche Implementierung und daher die Spezifikationen auch dann erfolgreich sein könnten, wenn die ursprüngliche Implementierung einen Fehler zurückgegeben hätte (oder gar nicht existiert). Es ist einfach falsch, sich über nicht existierende Methoden lustig zu machen.

Daher würde ich argumentieren, dass Sie nicht versuchen sollten, diese Ausnahme zu umgehen. Fügen Sie einfach eine name Methode Ihrer Klasse, die eine klare Ausnahme auslöst, wenn außerhalb der Testumgebung auszuführen:

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

'name' sollte wahrscheinlich eine Instanzmethode sein, die '' SOreadontohelp'' zurückgibt. – Stefan

+0

@Stefan: Ich stimme zu, das ist auch eine gute Idee. Hängt vom Fokus ab: zu betonen, dass Spezifikationen und Code synchron sind oder dass es etwas zu reparieren gibt ... – spickermann

1

Ich denke, dass, wenn der Test auf die MyModule Modul fokussiert schreiben, und das Modul stützt sich auf eine Instanzmethode in der Klasse, in die es eingefügt wird, dann denke ich, dass diese Methode in der anonymen Klasse, die Sie beim Testen des Moduls verwenden, mokiert werden sollte. Zum Beispiel:

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