Ruby:在代码块中更改类静态方法
给出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中,只有强大的模拟框架才能做到)。 但它是ruby,我希望这些令人讨厌的东西可用
您可能想看看像Mocha这样的Ruby模拟框架,但是在使用纯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 = <
您还可以编写一个小的包装器方法,它将替换方法,屈服于块,然后确保之后恢复原始方法,例如
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
正如在原始答案中所提到的,您可能会找到一个框架来为您执行此操作,但希望上面的代码无论如何都是有趣和有用的。