ruby – Rspec:allow和allow_any_instance_of之间的差异

我有一个简单的
MySQL包装器类,它将运行查询并返回结果.

class Rsql
  def initialize(db)
    @client = Mysql2::Client
    @db = db
  end

  def execute_query()
    client = @client.new(@db)
    client.query("select 1")
  end

end

我想测试一些涉及查询结果的东西,但我不想实际连接到数据库来获得结果.我试过这个测试,但它不起作用:

RSpec.describe Rsql do

  it "does it" do
    mock_database = double
    rsql = Rsql.new(mock_database)

    mock_mysql_client = double
    allow(mock_mysql_client).to receive(:query).and_return({"1" => 1})

    allow_any_instance_of(Mysql2::Client).to receive(:new).and_return(mock_mysql_client)
    expect(rsql.execute_query).to eq({"1" => 1})
  end

end

用“allow”替换“allow_any_instance_of”有效.我的印象是allow_any_instance_of()是某种全局“假装这个类在整个程序中以这种方式运行”,而allow()是针对类的特定实例.

有人可以向我解释这种行为吗?我是Rspec的新手,所以如果这个答案显而易见,我会道歉.我试着寻找答案,但我找不到合适的搜索字符串来找到答案.也许我不知道什么时候才发现它.

谢谢!

最佳答案 从RSpec 3.3开始,不推荐使用any_instance,不建议在测试中使用.

From the docs

any_instance is the old way to stub or mock any instance of a class
but carries the baggage of a global monkey patch on all classes. Note
that we generally recommend against using this feature.

您应该只需要使用allow(some_obj),文档中有一些很好的例子(见here).

如:

RSpec.describe "receive_messages" do
  it "configures return values for the provided messages" do
    dbl = double("Some Collaborator")
    allow(dbl).to receive_messages(:foo => 2, :bar => 3)
    expect(dbl.foo).to eq(2)
    expect(dbl.bar).to eq(3)
  end
end

编辑,如果你真的想使用any_instance,那么这样做:

(Mysql2::Client).allow_any_instance.to receive(:something)
点赞