RSpec-如何测试是否调用了其他类的方法?

我想猴子修补String#select方法,并想创建一个测试套件来检查它是否不使用Array#select。

我尝试使用to_not receiveto_not receive(Array:select)一起使用to_not receive(:select)创建了一堆测试。我还尝试使用数组(string.chars)代替string。 Google和堆栈溢出没有带来答案。

describe "String#select" do
  it "should not use built-in Array#select" do
    string = "HELLOworld".chars
    expect(string).to_not receive(Array:select)
  end
end

预期:一个有效的测试套件,用于检查整个方法中是否未使用Array#方法。

实际输出:我收到一个错误,指出没有使用足够的参数。输出日志如下:

  1) RECAP EXERCISE 3 Proc Problems: String#select should not use built-in Array#select
     Failure/Error: expect(string).to_not receive(Array:select)
     ArgumentError:
       wrong number of arguments (given 0,expected 1..4)
     # ./spec/problems_spec.rb:166:in `select'
     # ./spec/problems_spec.rb:166:in `block (4 levels) in <top (required)>'

fwangeling 回答:RSpec-如何测试是否调用了其他类的方法?

首先:测试应该检查所调用方法的结果,而不是检查其实现方式。过度依赖它会给您带来麻烦。

但是这样做可能有合法的理由,但是请您认真考虑一下,可以用其他方式进行测试:

假设String#select在内部使用Array#select,而在某些情况下后者是有问题的。最好进行测试,以触发错误的方式设置Universe并检查是否存在错误行为。然后打上String#select并测试绿色。这是更好的方法,因为该测试现在告诉每个人为什么,您不应该在内部使用Array#select。而且,如果该错误已被删除,则在阳光下最容易移除补丁并检查规格是否仍为绿色。

话虽如此,如果您仍然需要使用expect_any_instance_of来完成此操作,例如,此规范将失败:

class String
  def select(&block)
    split.select(&block) # remove this to make the spec pass
  end
end

specify do
  expect_any_instance_of(Array).not_to receive(:select)

  'foo'.select
end

如果您不想使用expect_any_instance_ofbecause reasons),则可以暂时覆盖类中的方法以使失败:

class String
  def select(&block)
    #split.select(&block)
  end
end

before do
  class Array
    alias :backup_select :select

    def select(*)
      raise 'No'
    end
  end
end

after do
  class Array
    alias :select :backup_select # bring the original implementation back
  end
end

specify do
  expect { 'foo'.select }.not_to raise_error
end

需要使用别名来恢复原来的实现,因此您不会弄混在之后运行的规范。

但是您可以看到这种方法的复杂性和混乱性。

无论如何-您要实现的目标很可能是 一个设计问题,但是如果没有更多细节很难说清。

本文链接:https://www.f2er.com/3142344.html

大家都在问