2013-05-16 21 views
32

Tak, wiem, że testowanie metod prywatnych nie jest to dobry pomysł (i czytam ten wątek - http://www.ruby-forum.com/topic/197346 - i kilka innych)Testowanie prywatnych metoda w Ruby (rspec)

ale jak mogę przetestować poniższy kod?

Używam xmpp4r. W moim metoda publicznego #listen zacznę otrzymywać jabber wiadomości tak:

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 - uruchamia blok, gdy wiadomość pochodzą (w innym wątku)

Więc testowania #listen metody jest to trudne i dalsze testy xmpp4r niż mój #do_things_with_message

Jak zrobić wszystko prawo i próbę #do_things_with_message? :) (http://www.ruby-forum.com/topic/197346#859664)

byłaby prywatne metody do nowego obiektu essentialy byłoby jak czyni je publiczną (i klasę z jednej metody - to bezsensownie

EDIT: To jest bardziej teoretyczne pytanie o czystą kod i poprawne testy. W moim pierwszym linku ludzie twierdzą, że testują metody prywatne słabo. Nie chcę oszukiwać z #send, ale też nie widzę żadnych realne sposoby byłaby

+0

To nie jest prawdziwe pytanie. Wątek, do którego odnośnik już posiadasz, daje ci kilka technik do osiągnięcia tego, co chcesz, i kilka dobrych rad, jak kształtować swój projekt wokół problemu. Możesz oszukiwać i używać 'send' lub włączać publiczną metodę w swoich testach, lub możesz refaktoryzować. – dbenhur

+0

@dbenhur Nie chcę oszukiwać, ale także nie widzę żadnych opłacalnych sposobów na refaktoryzację – Andrey

+0

Jeśli twój kod jest wystarczająco złożony, musisz przetestować metodę prywatną (to znaczy, nie jest to tylko prosty model.znaleźć lub cokolwiek innego), to może i tak być na tyle skomplikowanym, że warto go wydobyć na osobną klasę. – Jason

Odpowiedz

75

można wywołać prywatną metodę w Ruby przy użyciu the send method. Coś takiego:

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

W teście, który będzie wyglądał mniej więcej tak:

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

Wiem o '# send'. To bardziej teoretyczne pytanie o czysty kod i odpowiednie testy ... – Andrey

+0

@Andrey Czy mógłbyś podać jakiekolwiek odniesienie – Richie

1

Prawdopodobnie usłyszał tę myśl we wszystkich zasobów, które można wymienić, ale właściwego „teoretyczny” sposób to zrobić będzie przetestować, czy @client otrzymuje add_message_callback, a następnie pośrednio przetestować prywatne metody za pomocą testów integracyjnych. Istotą testów jednostkowych jest to, że można zmienić realizacji, a twoje testy będą nadal przechodzić

+0

"byłoby przetestowanie, że @client otrzymuje add_message_callback" - może masz rację ... ale wciąż testujesz klejnot xmpp4r, serwer jabber i moja sieć itp. rzeczywista praca i rzeczywiste wyjście robią '# do_things_with_message'. '# add_message_callback' po prostu uruchom nowy wątek – Andrey

+1

Dodanie detektora nie jest kodem gem, inaczej nie musiałbyś go pisać. Jeśli chcesz przetestować swoją prywatną metodę, upublicznij ją lub użyj 'send (: do_things_with_message, args)' – enthrops

12

Pomijając kwestię tego, czy powinien być testowanie prywatną metodę, to jest bardzo możliwe w Ruby do tymczasowo uczynić prywatną metodę publiczną. Oto co mam na myśli:

# 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 

byłoby użyć publicize_methods tak:

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