Ruby RSpec-如何测试不同的类';方法被调用了吗?

Ruby RSpec-如何测试不同的类';方法被调用了吗?,ruby,testing,rspec,Ruby,Testing,Rspec,我想对一个String#select方法进行修补,并想创建一个测试套件来检查它是否使用Array#select 我尝试创建一系列测试,使用不接收,同时使用不接收(数组:选择)和不接收(:选择)。我还尝试使用数组(string.chars)代替字符串。Google和stack overflow没有给出答案 describe "String#select" do it "should not use built-in Array#select" do string = "HELLOwor

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

我尝试创建一系列测试,使用
不接收
,同时使用
不接收(数组:选择)
不接收(:选择)
。我还尝试使用数组(string.chars)代替字符串。Google和stack overflow没有给出答案

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)>'

1)回顾练习3过程问题:字符串#选择不应使用内置数组#选择
失败/错误:预期(字符串)。不接收(数组:选择)
参数错误:
参数数量错误(给定0,应为1..4)
#./spec/problems_spec.rb:166:in'select'
#./spec/problems_spec.rb:166:in'block(4层)in'

首先:测试应该检查调用的方法的结果,而不是它们的实现方式。过分依赖这一点会给你带来麻烦

但这样做可能有正当的理由,但仔细想想,你可以用另一种方式来测试:

假设
String#select
在内部使用
Array#select
,后者在某些情况下是有缺陷的。最好做一个测试,以一种触发bug的方式设置宇宙,并检查bug行为是否不存在。然后修补
字符串#选择
并使测试呈绿色。这是一种更好的方法,因为测试现在告诉每个人为什么不应该在内部使用
Array#select
。如果bug被移除,那么移除补丁并检查规范是否仍然是绿色的是最简单的事情

也就是说,如果您仍然需要,您可以使用
的任何实例来完成,例如,此规范将失败:

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
如果您不想使用
()的任何实例,可以临时覆盖类中的方法以使其失败:

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
恢复原始实现时需要使用别名,这样就不会弄乱在这一次之后运行的规范

但你可以看到这种方法是多么复杂和混乱


无论如何,你想要达到的目标很可能是一个设计问题,但是如果没有更多的细节就很难说了

你怎么能让修补程序数组不响应
select
?你不能用方法内省来检查
“mystring”.method(:select).source\u位置
指向包含monkeypatch的模块吗?