Ruby:在代码块中更改类静态方法 [英] Ruby: Alter class static method in a code block
问题描述
给出Thread类的当前方法. 现在在测试中,我想这样做:
Given the Thread class with it current method. Now inside a test, I want to do this:
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& Java)来说,这听起来很复杂C#(在Java中,只有强大的模拟框架才能做到).但是它是红宝石,我希望这样的讨厌东西会可用
Basically, I want to alter the method of a class inside a test method and recover it after that. I know it sound complex for another language, like Java & C# (in Java, only powerful mock framework can do it). But it's ruby and I hope such nasty stuff would be available
推荐答案
您可能想看看Ruby模拟框架,例如此处)例如
You might want to take a look at a Ruby mocking framework like Mocha, but in terms of using plain Ruby it can be done using alias_method
(documentation here) e.g.
事先:
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
更新以说明在测试中执行此操作
如果要在测试中执行此操作,可以定义一些辅助方法,如下所示:
If you want to do this from within a test you could define some helper methods as follows:
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
获取类和方法名称,然后将原始方法重新命名为别名.
replace_class_method
is expecting a class constant, the name of a class method and the new method definition as a string. restore_class_method
takes the class and the method name and then aliases the original method back in place.
您的测试将遵循以下条件:
Your test would then be along the lines of:
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
您还可以编写一个小的包装方法,该方法将替换一个方法,屈服于一个块,然后确保随后恢复原始方法,例如.
You could also write a little wrapper method which would replace a method, yield to a block and then ensure that the original method was reinstated afterwards e.g.
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
在您的测试方法中,可以将其用作:
Inside your test method this could then be used as:
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
如原始答案中所述,您可能可以找到一个框架为您完成此操作,但是希望以上代码无论如何都是有趣且有用的.
As mentioned in the original answer, you can probably find a framework to do this for you but hopefully the above code is interesting and useful anyway.
这篇关于Ruby:在代码块中更改类静态方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!