下面是一些简单的代码,对于指定的每个参数,都会添加以该参数命名的特定get/set方法。如果你写attr_option :foo, :bar
,然后你会看到Config
#foo/foo=
和#bar/bar=
实例方法:如何编写RSpec测试来单元测试这个有趣的元编程代码?
module Configurator
class Config
def initialize()
@options = {}
end
def self.attr_option(*args)
args.each do |a|
if not self.method_defined?(a)
define_method "#{a}" do
@options[:"#{a}"] ||= {}
end
define_method "#{a}=" do |v|
@options[:"#{a}"] = v
end
else
throw Exception.new("already have attr_option for #{a}")
end
end
end
end
end
到目前为止,一切都很好。我想写一些RSpec测试来验证这段代码实际上正在做它应该做的事情。但是有一个问题!如果我在其中一种测试方法中调用attr_option :foo
,则现在在Config中永远定义该方法。所以,因为foo
已经定义的后续测试将当它不应该失败:
it "should support a specified option" do
c = Configurator::Config
c.attr_option :foo
# ...
end
it "should support multiple options" do
c = Configurator::Config
c.attr_option :foo, :bar, :baz # Error! :foo already defined
# by a previous test.
# ...
end
有没有一种方法,我可以给每个测试Config
类的匿名“克隆”,这是独立于其他的?
+1对于坚实的建议和新颖的方法;我不会想到创建匿名类,并且正在考虑像创建类的匿名模块然后销毁它。这显然是更好的解决方案。 – 2010-05-23 15:37:25