如何模拟 Ruby 模块函数?

11

如何在我的项目中模拟自己编写的模块内的函数?

假设有该模块和该函数

module ModuleA::ModuleB
  def self.my_function( arg )
  end
end

它被称为

ModuleA::ModuleB::my_function( with_args )

当我写规范测试函数时,该如何模拟它?


对于我来说,将其二次化 (obj = double("ModuleA::ModuleB")) 没有意义,因为该函数是在模块上调用的,而不是在对象上调用的。

我已经尝试使用存根 (ModuleA::ModuleB.stub(:my_function).with(arg).and_return(something)),显然,它没有起作用。 stub 在那里未被定义。

然后我尝试使用 should_receive。同样遇到 NoMethodError

模拟一个模块及其函数的首选方式是什么?

2个回答

11

根据你在问题中描述的模块

module ModuleA ; end

module ModuleA::ModuleB
  def self.my_function( arg )
  end
end

需要测试的函数调用了模块中的函数

def foo(arg)
  ModuleA::ModuleB.my_function(arg)
end

然后你可以像这样测试foo是否调用了myfunction

describe :foo do
  it "should delegate to myfunction" do
    arg = mock 'arg'
    result = mock 'result'
    ModuleA::ModuleB.should_receive(:my_function).with(arg).and_return(result)
    foo(arg).should == result
  end
end

1
那基本上就是我尝试过的。感谢总结。然而我的问题是,我把should_receive放在了一个before :all块中。显然这是行不通的。我真是太蠢了。 - Torbjörn
@Torbjoern,没错。我也遇到过这种情况。很高兴你解决了它。 - Wayne Conrad
在当前的rspec(3.6)中,使用rspec-mocks旧的:should语法的should_receive被弃用,而没有明确启用该语法。请使用新的:expect语法或明确启用:should - reducing activity

1

如果使用rspec 3.6,请参阅如何在RSpec expect语法中模拟类方法?以获取更多信息。

为了避免仅链接回答,这里是Andrey Deineko的答案副本:

allow(Module)
  .to receive(:profile)
  .with("token")
  .and_return({"name" => "Hello", "id" => "14314141", "email" => "hello@me.com"})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接