Ruby 我如何在单元测试中临时用其他方法替换方法?

Ruby 我如何在单元测试中临时用其他方法替换方法?,ruby,unit-testing,minitest,Ruby,Unit Testing,Minitest,使用Mocha模拟或存根跨网络的函数非常有用: def test_something NetworkClass.stub(:fetch_something, "contrived example") assert_equal "contrived example", NetworkClass.fetch_something end 但更多的时候,我的网络交叉函数需要一些输入,这些输入会影响函数返回的内容。对于我的单元测试,我只准备了一个包含测试套件需要运行的输入和输出的散列。问题是,

使用Mocha模拟或存根跨网络的函数非常有用:

def test_something
  NetworkClass.stub(:fetch_something, "contrived example")

  assert_equal "contrived example", NetworkClass.fetch_something
end
但更多的时候,我的网络交叉函数需要一些输入,这些输入会影响函数返回的内容。对于我的单元测试,我只准备了一个包含测试套件需要运行的输入和输出的散列。问题是,现在我不能再使用Mochas
.stub
.expects
,因为它们不允许我替换实际执行某些操作的函数

目前我正在做这样的事情:

def setup
  @subject = NetworkClass.new

  test_data = fetch_test_data

  @subject.define_singleton_method(:fetch_something) { |input|
    test_data[input] or fail "Unexpected stub input: #{input}"
  }
end
但是这永久地改变了主题,所以我不能使用这个方法来存根模块函数或类方法

有没有一种方法可以“暂时”用另一种方法代替一种方法,这种方法就像摩卡的
.stub

如果有人想告诉我,这是一种不好的测试方法,并告诉我一个更好的方法,我想我也会接受这个答案。这已经困扰了我一段时间了



避免这种情况的一个显而易见的方法是在每个测试函数中存根该方法,并记住一个特定的输入,但在我看来,这就像是许多额外的“样板”测试代码,没有实际的好处。同样,通过这种方式,我可以确保每次运行测试套件时,我不会忘记将方法存根在某个地方,并意外地通过网络。

如您所说,如果您知道测试中的输入,您可能仍然可以使用mocha的功能

NetworkClass.stub(:fetch\u something).with(input).returns(test\u data[input])

仅当使用正确的输入调用fetch_something时,才会执行此操作。您可以通过这种方式使用不同的输入创建多个存根

不过,一般来说,这不应该是一个问题,因为您的测试应该是可预测和可重复的。这意味着每个单独的测试用例应该运行相同的代码路径,从而为您的NetworkClass触发相同的参数。此外,每个测试用例都应该运行单个代码路径,并尽可能集中精力

编辑

不确定您的测试框架是什么,但是在每个测试用例之前应该有设置和拆卸的机制。通过这种方式,您可以使用您的方法,并在每个测试用例之后还原类。

在RSpec3中,您可以使用

或(用于更多颗粒试验)


我认为答案是用相同的接口声明另一个类。至少我是这样做的。
allow(NetworkClass).to receive(:fetch_something).with(input) { test_data[input] }
allow(NetworkClass).to receive(:fetch_something) do |arg|
  expect(arg).to eql test_data[input]
end