2013-05-16 19 views
32

Sì, lo so, che metodi di prova privati ​​non è una buona idea (e io letto questa discussione - http://www.ruby-forum.com/topic/197346 - e alcuni altri )Testing metodo privato in Ruby (RSpec)

Ma come posso testare il seguente codice?

Io uso xmpp4r. Nel mio metodo pubblico #listen comincio ricevere jabber messaggi in questo modo:

def listen 
    @client.add_message_callback do |m| 
    do_things_with_message(m) 
    end 
end 

private 
def do_things_with_message(m) 
    # 
end 

#add_message_callback - esegue blocco, quando il messaggio venuto (in thread differente)

Quindi, il test #listen metodo è difficile e più test xmpp4r del mio #do_things_with_message

Come fare tutto bene e prova #do_things_with_message? :) (http://www.ruby-forum.com/topic/197346#859664)

refactoring metodi privati ​​a un nuovo oggetto essentialy sarebbe come io che li rende un pubblico (e di classe con un metodo - è insensatamente

EDIT: Questo è più una questione teorica sul codice pulito e il test corretti Nel mio primo link le persone sostengono che i metodi privati ​​del test sono scarsi. Non voglio barare con #send, ma anche io non vedo nessun vie percorribili di refactoring

+0

Questa non è una vera domanda. Il thread a cui ti colleghi già offre diverse tecniche per realizzare ciò che desideri e alcuni buoni consigli su come modellare il tuo design attorno al problema. Puoi imbrogliare e usare 'send' o attivare il metodo nei tuoi test oppure puoi refactoring. – dbenhur

+0

@dbenhur Non voglio imbrogliare, ma non vedo alcun metodo valido per refactor – Andrey

+0

Se il codice è abbastanza complesso è necessario testare il metodo privato (cioè non è solo un semplice modello.trovare o qualsiasi altra cosa), quindi potrebbe essere abbastanza complesso da valere la pena di estrapolarlo in una classe separata, comunque. – Jason

risposta

75

è possibile chiamare un metodo privato in Ruby utilizzando the send method. Qualcosa di simile a questo:

@my_object = MyObject.new 
@my_object.send(:do_things_with_message, some_message) 

In un test che sarebbe simile:

it "should do a thing" do 
    my_object = MyObject.new 
    my_object.send(:do_things_with_message, some_message) 
    my_object.thing.should == true 
end 
+4

So di '# send'. È una domanda più teorica sul codice pulito e sui test giusti ... – Andrey

+0

@Andrey Potresti fornire qualsiasi riferimento – Richie

1

probabilmente hai sentito questo pensiero in tutte le risorse che hai citato, ma il modo corretto "teorico" per farlo sarebbe quello di verificare che @client riceve add_message_callback e quindi indirettamente testare i metodi privati ​​con test di integrazione. Il punto di unit testing è che si può cambiare l'implementazione e le vostre prove sarà ancora passare

+0

"sarebbe per verificare che @client riceva add_message_callback" - forse hai ragione ... ma sta ancora testando xmpp4r gem, jabber server e la mia rete, ecc. il lavoro reale e l'output reale fanno '# do_things_with_message'. '# add_message_callback' avvia appena il nuovo thread – Andrey

+1

L'aggiunta di un listener non è un codice gemma, altrimenti non dovresti scriverlo. Se vuoi testare il tuo metodo privato, rendilo pubblico o usa 'send (: do_things_with_message, args)' – enthrops

12

Mettendo da parte la questione di se o non si dovrebbe essere la prova di un metodo privato, è molto possibile in Ruby per rendere temporaneamente pubblico un metodo privato. Ecco cosa intendo:

# Metaprogrammatical magic to temporarily expose 
# a Class' privates (methods). 
class Class 
    def publicize_methods 
    saved_private_instance_methods = self.private_instance_methods 
    self.class_eval { public *saved_private_instance_methods } 
    yield 
    self.class_eval { private *saved_private_instance_methods } 
    end 
end 

si usa publicize_methods come questo:

ClassToTest.publicize_methods do 
    ... 
    do_private_things_with_message(m).should ??? 
    ... 
end