2013-05-16 3 views
32

Да, я знаю, что тестирование закрытых методов, это не очень хорошая идея (и я прочитать эту тему - http://www.ruby-forum.com/topic/197346 - и некоторые другие)Testing частный метод в Рубине (RSpec)

Но как я могу проверьте следующий код?

Я использую xmpp4r. В моем общедоступный метод #listen я начинаю получать Jabber сообщения следующим образом:

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 - работает блок, когда сообщение придет (в другом потоке)

Таким образом, тестирование #listen метода это трудно и больше испытывать xmpp4r чем мой #do_things_with_message

Как сделать все в порядке и тест #do_things_with_message? :) (http://www.ruby-forum.com/topic/197346#859664)

реорганизовывать частные методы к новому объекту essentialy бы я сделать их публичное (и класс с одним методом - это бестолково

EDIT: Это более теоретический вопрос о чистом коде а правильные тесты. В моей первой ссылке люди утверждают, что тесты частных методов плохо. Я не хочу обманывать с #send, но и я не вижу никаких жизнеспособных способов реорганизовать

+0

Это не реальный вопрос. Поток, на который вы ссылаетесь, уже дает вам несколько методов для достижения того, что вы хотите, и некоторые полезные советы о том, как формировать дизайн вокруг проблемы. Вы можете обмануть и использовать 'send' или включить метод в своих тестах, или вы можете реорганизовать. – dbenhur

+0

@dbenhur Я не хочу обманывать, но также я не вижу никаких жизнеспособных способов рефакторинга – Andrey

+0

Если ваш код достаточно сложный, вам нужно проверить частный метод (т. Е. Это не просто простая модель.найти или что-то еще), тогда вполне может быть достаточно сложным, чтобы в любом случае стоить выходить в отдельный класс. – Jason

ответ

75

Вы можете назвать частный метод в рубин, используя the send method. Что-то вроде этого:

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

В тесте, который будет выглядеть примерно так:

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

Я знаю о '# send'. Это более теоретический вопрос о чистом коде и правильных тестах ... – Andrey

+0

@ Andrey Не могли бы вы предоставить любую ссылку – Richie

1

Вы, наверное, слышали эту мысль во всех ресурсах, которые вы упоминаете, но правильный «теоретический» способ сделать это было бы проверить, что @client получает add_message_callback, а затем косвенно тестирует ваши частные методы с интеграционными тестами. Весь смысл модульного тестирования является то, что вы можете изменить реализацию, и тесты будут еще проходить

+0

«было бы проверить, что @client получает add_message_callback» - возможно, вы правы ... но он все еще тестирует gmp, jabber-сервер и моя сеть и т. д. реальная работа и реальный вывод делают '# do_things_with_message'. '# add_message_callback' просто запускает новый поток – Andrey

+1

Добавление слушателя не является кодом драгоценного камня, иначе вам не нужно было бы его писать. Если вы хотите проверить свой частный метод, сделайте его общедоступным или используйте 'send (: do_things_with_message, args)' – enthrops

12

Отложив вопрос о том, действительно ли вы должны испытывать частный метод, очень возможно, в Руби временно публиковать закрытый метод. Вот что я имею в виду:

# 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 

Вы могли бы использовать publicize_methods так:

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