创建自定义匹配器以测试某些局部变量:
RSpec::Matchers.define :set_the_local_variable do |variable|
match do |actual|
@actual = controller.binding.local_variable_get(variable)
@actual == @expected
end
failure_message do |actual|
"set '#{@actual}' equal to #{@expected}. However, it did not: \n '#{@actual.inspect}' \n '#{@expected.inspect}'"
end
failure_message_when_negated do |actual|
"set '#{@actual}' not equal to #{@expected}. However, it did: \n '#{@actual.inspect}' \n '#{@expected.inspect}'"
end
description do
"set the instance '#{@actual}' to equal '#{expected}'"
end
def to(expected)
@expected = expected
self
end
end
然而,这一行:
controller.binding.local_variable_get(variable)
给了我这个错误:
private method `binding' called for #<StaticController:0x00000104b5a108>
我如何解决这个问题? binding.local_variable_get
在irb中工作正常:
2.1.1 :001 > foo = 'bar'
=> "bar"
2.1.1 :002 > binding.local_variable_get(:foo)
=> "bar"
有人能解释一下这里发生了什么吗?我理解类,实例和继承以及私有类方法,但我不确定如何使其工作。
我想找出包含绑定的类,并在匹配块中使用该类扩展控制器?那样的东西?
答案 0 :(得分:1)
binding
的文档说:
返回一个Binding对象,描述变量和方法绑定 在通话点。
(强调补充)
在IRB中尝试:
> self
main
> binding
=> #<Binding:0x007fa89a8be670>
> self.binding
NoMethodError: private method `binding' called for main:Object
您当然可以直接发送消息:
> self.send(:binding)
=> #<Binding:0x007fa89a890b30>
但这与输入binding
相同。
您在IRB中键入的内容是在顶级main
方法的上下文中完成的。执行controller.binding
时,您将在RSpec为您创建的测试控制器实例上调用该方法。但是,上下文是RSpec示例实例,而不是控制器实例,它(可能是?)不是您想要的。
实际上这完全是学术性的:在测试时进入实例并检查局部变量的值是不明智的。如果您非常想要这样做,那么恕我直言就表明需要进行一些重构。