如何避免使用allow_any_instance_of?

时间:2016-04-15 08:26:38

标签: ruby rspec rspec-mocks

想象一下,我们有以下代码:

class A
  def create_server
    options = {
      name: NameBuilder.new.build_name
    }
    do_some_operations(options)
  end
end

为了测试这些方法,我曾经使用allow_any_instance_of

it 'does operations' do
  allow_any_instance_of(NameBuilder).to receive(:build_name)
  # test body
end

但是文档建议我们不要使用它because of several reasons。然后如何避免allow_any_instance_of?我只找到了一个解决方案:

class A
  def create_server
    options = {
      name: builder.build_name
    }
    do_some_operations
  end

  private

  def builder
    NameBuilder.new
  end
end

但是使用这样的方法代码很快就会变得几乎无用的方法(特别是当你在所描述的类中主动使用不同对象的组合时)。

2 个答案:

答案 0 :(得分:4)

根据Uzbekjon's answer(我同意)没有依赖注入,你也可以考虑删除对NameBuilder.new的调用,这样你就可以直接控制{{1}的实例在测试中:

NameBuilder

答案 1 :(得分:3)

如果难以测试,则表示您的班级设计存在问题。在您的情况下,当您在类中的特定类上测试特定方法调用时,您正在测试如下:

allow_any_instance_of(NameBuilder).to receive(:build_name)

您的测试确切知道该方法是如何在内部实现的。您的类应该封装逻辑并隐藏它。你正好相反。

不应该测试任何内部方法逻辑。只是测试行为。提供输入并测试输出的正确性。

如果你真的想在NameBuilder类上测试该方法调用,那么注入该依赖项并使你的类更易于测试。这也遵循OOP原则。

class A
  def create_server(builder)
    do_some_operations(name: builder.build_name)
  end
end