gpt4 book ai didi

ruby - 我如何编写 RSpec 测试来对这个有趣的元编程代码进行单元测试?

转载 作者:数据小太阳 更新时间:2023-10-29 08:34:48 25 4
gpt4 key购买 nike

这是一些简单的代码,对于每个指定的参数,将添加以该参数命名的特定 get/set 方法。如果你写 attr_option :foo, :bar , 然后你会看到 #foo/foo=#bar/bar= Config 上的实例方法:

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 的匿名“克隆”?哪个类独立于其他类?

最佳答案

“克隆”您的 Config 类的一种非常简单的方法是简单地使用匿名类对其进行子类化:

c = Class.new Configurator::Config
c.attr_option :foo

d = Class.new Configurator::Config
d.attr_option :foo, :bar

这对我来说没有错误。这是有效的,因为设置的所有实例变量和方法都绑定(bind)到匿名类而不是 Configurator::Config

语法 Class.new Foo 创建一个匿名类,将 Foo 作为父类(super class)。

此外,在 Ruby 中throwing 一个Exception 是不正确的; Exceptionraised。 throw 应该像 goto 一样使用,例如跳出多个嵌套。阅读this Programming Ruby section以获得对差异的良好解释。

作为另一种吹毛求疵的风格,尽量不要在 Ruby 中使用 if not ...。这就是 unless 的用途。但 unless-else 也是糟糕的风格。我会将你的 args.each block 的内部重写为:

raise "already have attr_option for #{a}" if self.method_defined?(a)
define_method "#{a}" do
@options[:"#{a}"] ||= {}
end

define_method "#{a}=" do |v|
@options[:"#{a}"] = v
end

关于ruby - 我如何编写 RSpec 测试来对这个有趣的元编程代码进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2891960/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com