Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 如何重置模拟类方法的期望值?_Ruby_Unit Testing_Rspec_Mocking - Fatal编程技术网

Ruby 如何重置模拟类方法的期望值?

Ruby 如何重置模拟类方法的期望值?,ruby,unit-testing,rspec,mocking,Ruby,Unit Testing,Rspec,Mocking,如果这很简单,我很抱歉。我对ruby和rspec都是新手,rspec似乎是一个非常“模糊”的世界(尤其是来自.net背景的时候) 在我的“规范”中,我有: before(:each) do expect(File).to receive(:exist?).with("dummy.yaml").and_return (true) end 这适用于我所有的“示例”,除了一个我希望它返回false的示例 expect(File).to receive(:exist?).with("non_e

如果这很简单,我很抱歉。我对ruby和rspec都是新手,rspec似乎是一个非常“模糊”的世界(尤其是来自.net背景的时候)

在我的“规范”中,我有:

before(:each) do
    expect(File).to receive(:exist?).with("dummy.yaml").and_return (true)
end
这适用于我所有的“示例”,除了一个我希望它返回false的示例

expect(File).to receive(:exist?).with("non_existent.yaml").and_return (false)
这显然没有通过我的测试,因为虽然满足了“不存在.yaml”的预期,但“dummy.yaml”并没有:

但这给了我:

NoMethodError:
   undefined method `proxy_for' for RSpec::Mocks:Module

我在文档中找不到这样做的地方,过去的行为表明,这种解决方案在未来也可能会发生变化,但显然,这是您当前可以做到的:

RSpec::Mocks.space.proxy_for(your_object).reset
不过,我会按照@broisasse的说法,考虑重新设计测试,旨在将期望从
之前的
块中转移出来。正如您所说,
before
块是用于设置的,设置是一个非常奇怪的放置期望值的地方

我不确定您是如何设计的,但我可以建议两种可能的替代方案:

  • 如果测试很简单,并且无论如何都可以工作,那么您应该创建一个具有此明确预期的测试,同时为其他测试保留它:

    before(:each) do
      allow(File).to receive(:exist?).with("dummy.yaml").and_return (true)
    end
    
    it "asks if file exists" do
      expect(File).to receive(:exist?).with("dummy.yaml").and_return (true)
      # do the test...
    end
    
  • >P>如果每个测试都应该运行预期,因为每个场景中的变化是上下文,您应该考虑使用:


您可能还想知道是否有更推荐/有文档记录的解决方案来重置模拟对象…

这对我从类中卸载特定方法很有效:

mock = RSpec::Mocks.space.proxy_for(MyClass)
mock.instance_variable_get(:@method_doubles)[:my_method].reset
注:逻辑相同
RSpec::Mocks.space.proxy_for(MyClass).reset
重置所有方法

在我进行扩展时,我发现我可以使用
RSpec::Mocks.space.registered?
检查方法是否为mock,并使用
RSpec::Mocks.space.proxy_for(my_mocked_var).reset
重置它的值

这是:

示例:重置模拟值 例如,如果我们想
重置
这个模拟,它将被取消
默认值,我们可以使用
helper的
RSpec::Mocks.space.proxy\u
找到我们的模拟,然后重置它:

# when
#   Rails.configuration.action_controller.allow_forgery_protection == false
# and
#   allow(Rails.configuration.action_controller).to receive(:allow_forgery_protection).and_return(true)

RSpec::Mocks.space.registered?(Rails.configuration.action_controller)
# => true

Rails.configuration.action_controller.allow_forgery_protection
# => true

RSpec::Mocks.space.proxy_for(Rails.configuration.action_controller).reset

Rails.configuration.action_controller.allow_forgery_protection
# => false
但是请注意,即使重置了模拟值 模拟仍然
已注册?

RSpec::Mocks.space.registered?(Rails.configuration.action_controller)
# => true
使用“expect_any_instance”时,我成功地使用以下方法更改模拟(例如,我们的示例:发布Twitter帖子并返回不同的tweet id)

期望(Twitter::REST::Client.)的任何实例接收(:update)。并返回(Hashie::Mash.new(id:“12”))
#发布推特
RSpec::Mocks.space.verify\u all
RSpec::Mocks.space.reset_all
期望(Twitter::REST::Client.)的任何实例接收(:update)。并返回(Hashie::Mash.new(id:“12346”))
#再发一条推

您不应在
块之前使用
预期在
中接收
。这属于测试。try
RSpec::Mocks.space.proxy_for(您的_对象)。reset
BroiSatse:我假设'before'类似于'[Setup]'(nUnit:.net):不同测试中常见的设置应该放在这里,有助于保持测试干燥,并灵活地进行更改?还是RSpec使用了其他术语来描述我想要实现的目标?@UriAgassi谢谢,这很有效!请你把它作为答案贴出来,这样我就可以接受了。另外,我想知道为什么简单地重置一个mock会有如此繁琐的语法?这不应该是直接的函数调用吗?还是我在试图让RSpec表现得像nUnit(和其他测试框架)?
mock = RSpec::Mocks.space.proxy_for(MyClass)
mock.instance_variable_get(:@method_doubles)[:my_method].reset
# when
#   Rails.configuration.action_controller.allow_forgery_protection == false
# and
#   allow(Rails.configuration.action_controller).to receive(:allow_forgery_protection).and_return(true)

RSpec::Mocks.space.registered?(Rails.configuration.action_controller)
# => true

Rails.configuration.action_controller.allow_forgery_protection
# => true

RSpec::Mocks.space.proxy_for(Rails.configuration.action_controller).reset

Rails.configuration.action_controller.allow_forgery_protection
# => false
RSpec::Mocks.space.registered?(Rails.configuration.action_controller)
# => true