Ruby: Изменить статический метод класса в блоке кода - PullRequest
2 голосов
/ 10 июня 2010

Учитывая класс Thread с его текущим методом.Теперь внутри теста я хочу сделать это:

def test_alter_current_thread
  Thread.current = a_stubbed_method
  # do something that involve the work of Thread.current
  Thread.current = default_thread_current
end

По сути, я хочу изменить метод класса внутри метода теста и восстановить его после этого.Я знаю, что это звучит сложно для другого языка, например Java & C # (в Java это может сделать только мощная фальшивая среда).Но это рубин, и я надеюсь, что такие неприятные вещи будут доступны

1 Ответ

6 голосов
/ 10 июня 2010

Возможно, вы захотите взглянуть на Ruby Mocking Framework, например Mocha , но с точки зрения использования простого Ruby это можно сделать с помощью alias_method (документация здесь )

заранее:

class Thread
  class << self
    alias_method :old_current, :current
  end
end

затем определите ваш новый метод

class Thread
  def self.current
    # implementation here
  end
end

затем восстановите старый метод:

class Thread
  class << self
    alias_method :current, :old_current
  end
end

Обновление для иллюстрации выполнения этого из теста

Если вы хотите сделать это из теста, вы можете определить некоторые вспомогательные методы следующим образом:

def replace_class_method(cls, meth, new_impl)
  cls.class_eval("class << self; alias_method :old_#{meth}, :#{meth}; end")
  cls.class_eval(new_impl)
end

def restore_class_method(cls, meth)
  cls.class_eval("class << self; alias_method :#{meth}, :old_#{meth}; end")
end

replace_class_method ожидает константу класса, имя метода класса и определение нового метода в виде строки. restore_class_method принимает класс и имя метода, а затем псевдоним исходного метода на месте.

Тогда ваш тест будет выглядеть следующим образом:

def test
  new_impl = <<EOM
  def self.current
    "replaced!"
  end
EOM
  replace_class_method(Thread, 'current', s)
  puts "Replaced method call: #{Thread.current}"
  restore_class_method(Thread, 'current')
  puts "Restored method call: #{Thread.current}"
end

Вы также можете написать небольшой метод-обертку, который заменит метод, уступит блоку и затем обеспечит восстановление исходного метода, например,

def with_replaced_method(cls, meth, new_impl)
    replace_class_method(cls, meth, new_impl)
    begin
        result = yield
    ensure
        restore_class_method(cls, meth)
    end
    return result
end

Внутри вашего метода испытаний это можно использовать как:

with_replaced_method(Thread, 'current', new_impl) do
  # test code using the replaced method goes here
end
# after this point the original method definition is restored

Как упоминалось в первоначальном ответе, вы, вероятно, можете найти платформу для этого, но, надеюсь, приведенный выше код в любом случае интересен и полезен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...