如何在实例变量上存根方法?

时间:2013-06-30 18:40:59

标签: ruby mocha

所以我有这个简单的ruby类:

class GetRequestList
  def initialize(current_user, filter_hash)
    @authorizer = RequestAuthorizer.new(current_user)
    @filter    = RequestFilter.new(filter_hash)
  end
  def generate
    Request.send_chain(@authorizer.method_chain)
           .send_chain(@filter.method_chain)
  end
end

我想测试Request接收两个send_chain方法,而不是RequestAuthorizerRequestFilter实现。要做到这一点,我试图使用一些存根:

require 'test_helper'

class GetRequestListTest < ActiveSupport::TestCase

  test "request should be filtered by filter and role" do
    Request.expects(:send_chain).twice.returns([build(:request)])
    RequestFilter.stubs(:new)
    RequestFilter.any_instance.stubs(:method_chain).returns([])
    RequestAuthorizer.stubs(:new)
    RequestAuthorizer.any_instance.stubs(:method_chain).returns([])
    assert GetRequestList.new(:current_user, :filter).generate.size == 1
  end
end

你看错了什么。 stubs(:new)返回nilRequestAuthorizer的实例变量中没有RequestFilterGetRequestList的实例,我们收到错误消息。我无法弄清楚如何在实例变量上存根方法。 有什么建议吗?

3 个答案:

答案 0 :(得分:4)

不要将new删除而不返回任何值,而是让它返回一些内容,例如

mock_request_filter = mock()
RequestFilter.stubs(:new).returns(mock_filter)

这也使您能够阅读any_instance上的存根 - 只需将其设置为mock_request_filter

答案 1 :(得分:1)

这就是你应该在方法中包装实例变量的原因。看看这种方法。这样你的测试就不知道RequestFilter或RequestAuthorizer。现在你也资产,你把它们作为参数。请注意,我还在一个方法中包含了授权器和过滤器初始化。如果你的主初始化方法有更多的东西,你也可以将它们包装在另一个中。

class GetRequestList
  def initialize(current_user, filter_hash)
    initialize_authorizer
    initialize_filter
  end

  def generate
    Request.send_chain(authorizer_method_chain)
           .send_chain(filter_method_chain)
  end

  private

  def initialize_authorizer
    @authorizer = RequestAuthorizer.new(current_user)
  end

  def initialize_filter
    @filter = RequestFilter.new(filter_hash)
  end

  def authorizer_method_chain
    @authorizer.method_chain
  end

  def filter_method_chain
    @filter.method_chain
  end
end

和测试

require 'test_helper'

class GetRequestListTest < ActiveSupport::TestCase

  test "request should be filtered by filter and role" do
    get_request_list = GetRequestList.new(:current_user, :filter)
    get_request_list.stubs(:initialize_authorizer)
    get_request_list.stubs(:initialize_filter)

    get_request_list.stubs(:authorizer_method_chain).returns(:authorizer_method_chain)
    get_request_list.stubs(:filter_method_chain).returns(:filter_method_chain)

    Request.expects(:send_chain).with(:authorizer_method_chain).returns([build(:request)])
    Request.expects(:send_chain).with(:filter_method_chain).returns([build(:request)])

    assert get_request_list.generate.size == 1
  end
end

我还使用了一个符号来替换授权器和过滤器对象,因为你甚至不需要它们来模拟。它也可能是12之类的其他东西,但保留符号或字符串可以让你有点名字。

答案 2 :(得分:0)

您是否尝试过暴露实例变量以便将其存根?

GetRequestList.new(:current_user, :filter).tap do |it|
  def it.authorizer
    @authorizer
  end
  install_stubs(it.authorizer)
end.generate