Ruby on rails 用类扩展控制器

Ruby on rails 用类扩展控制器,ruby-on-rails,rspec,Ruby On Rails,Rspec,创建自定义匹配器以测试某些局部变量: 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|

创建自定义匹配器以测试某些局部变量:

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>
有人能解释一下这是怎么回事吗?我了解类、实例、继承和私有类方法,但我不知道如何使其工作


我想找出包含绑定的类,并在匹配块中用该类扩展控制器?类似的东西?

绑定的文档说明:

返回一个绑定对象,描述变量和方法绑定 在通话的时候

(增加重点)

在IRB中试试这个:

> self
main
> binding
=> #<Binding:0x007fa89a8be670>
> self.binding
NoMethodError: private method `binding' called for main:Object
>self
主要的
>装订
=> #
>自绑定
NoMethodError:为main:对象调用了私有方法“binding”
当然,您可以直接发送消息:

> self.send(:binding)
=> #<Binding:0x007fa89a890b30>
>self.send(:绑定)
=> #
但这与键入
绑定
是一样的

您在IRB中键入的内容是在顶级
main
方法的上下文中完成的。当您执行
controller.binding
时,您正在调用RSpec为您创建的测试控制器实例上的方法。但是,上下文是RSpec示例实例,而不是控制器实例,这(可能?)不是您想要的


实际上,尽管这都是学术性的:在测试时,深入实例并检查局部变量的值是不明智的。如果您很想这样做,这表明需要进行一些重构。

为什么要测试局部变量?使您无法重构脆弱的测试和代码。测试副作用,如创建的实例变量
赋值(:inst\u variable\u name\u here)
或重定向,它们在控制器规范中已经有匹配器。我知道,我不是在测试每个变量(心理),只是测试我真正想测试的一个散列。你能将其提取到服务对象中并在那里进行单元测试吗?我下意识的反应是,你实际上是在蒙骗rspec,而不是在正确的水平上测试你想要完成的事情。不管怎样,祝你好运。我认为你是对的,虽然我可以让它成为助手,但我只在一个地方使用它。这不是什么大问题。如果我得到答案,我会看看会发生什么:)是的,我明白了。这根本不是问题,但我有点好奇如何进行局部变量测试。如何将
binding.local\u variable\u get()
发送到控制器?这,
controller.send(:binding).send(:local_variables)
返回实际匹配器中的局部变量(
actual
variable
),我不知道rspec创建了控制器的另一个实例。为什么控制器中的局部变量不会出现在rspec实例中?rspec不会创建单独的控制器实例,如果我在这一点上混淆了,很抱歉。我试图得到的是调用
controller.send(:binding)
会返回与在示例上下文中调用
binding
相同的上下文,这与在matcher中调用它时看到的效果相同。这似乎违反直觉,但它是有意义的,因为
Binding
将上下文封装在调用它的位置,而不是接收器中的某个位置。例如,尝试
controller.send(:binding.eval('controller')
——返回相同的实例,对吗?
> self.send(:binding)
=> #<Binding:0x007fa89a890b30>