我应该如何测试仅以调用其他方法为唯一目的的便捷方法?

时间:2018-06-30 21:40:51

标签: ruby testing rspec

免责声明

这个问题是主观的。我知道应该避免在Stack上使用主观问题,但这是a)我已经苦苦挣扎了一段时间,不知道还有什么要问的; b)我认为这将被认为是一个建设性的主观问题,因此允许在堆栈上。


问题

我不知道如何测试一种便捷方法,该方法的唯一目的是在不同的对象上调用另一个方法。

据我所知,他们有两种解决方案,都有缺点:

  1. 对便捷方法及其调用的方法重新测试所有完全相同的逻辑。

  2. 测试便捷方法将调用并返回带有预期参数的原始方法。

选项1对我来说意义不大,尤其是当origin方法(便捷方法包装的方法)执行稍微复杂的逻辑并需要进行多个单元测试时,则没有意义。我为什么要在多个地方测试完全相同的逻辑?如果逻辑改变了怎么办?只在一个地方而不是多个地方进行测试会更好吗?

我倾向于选择选项2,但是明显的危险信号是您的测试实现,而不是行为。正如我一次又一次听到的(并且在大多数情况下倾向于一致),您不应该这样做。


问题示例

好,现在举一个例子来阐明我在说什么。

我目前正在研究一种API,可帮助程序员与Alexa进行交互。在我的API中设置对Alexa响应的基本方法是通过名为Alexa的类实例上的响应对象。例如,要将输出语音设置为“ hello world”,您将使用以下命令:

@alexa = Alexa.new
@alexa.response.set_speech("hello world")

除此之外,我在名为#say的Alexa类上提供了一种便捷方法,其结果完全相同:

@alexa.say("hello world")

这是幕后发生的事情:

# Alexa class
class Alexa
  attr_reader :response

  def initialize
    @response = Response.new
  end

  def say(speech)
    @response.set_speech(speech)
  end
end

# Response class
class Response
  attr_reader :response_hash

  def initialize
    @response_hash = {}
  end

  def set_speech(speech)
    @response_hash[:speech] = speech
  end
end

请注意,Alexa#say方法是如何包装的,他的唯一责任是使用传入的参数调用response#set_output_speech。

好,现在开始测试。

对于set_speech方法,测试很容易:

RSpec.describe Response do
  describe '#set_speech' do
    it 'adds the passed in argument to the response hash under key :speech' do
      subject = Response.new
      subject.set_speech("hello world")
      expect(subject.response_hash[:speech]).to eq("hello world")
    end
  end
end

说方法,我被撕毁了。

我可以重新测试该方法的行为(不是DRY并导致依赖于其他方法和对象的单元测试):

RSpec.describe Alexa do
  describe '#say' do
    it 'adds the passed in argument to the response hash of @response under key :speech' do
      subject = Alexa.new
      subject.say("hello world")
      expect(subject.response.response_hash[:speech]).to eq("hello world")
    end
  end
end

或者我可以用提供的选项测试说调用response#set_speech,据我所知,这是测试实现,而不是行为:

RSpec.describe Alexa do
  describe '#say' do
    it 'calls #set_speech on @response' do
      subject = Alexa.new
      expect(subject.response).to receive(:set_speech).with("hello world")
      subject.say("hello world")
    end
  end
end

我的问题

TL; DR-我应该如何测试一种便捷方法,其唯一目的是调用其他方法?

重新测试行为并进行重复和相关的单元测试,还是测试便捷方法调用原始方法,从而测试实现而非行为,是否更好?

或者也许我还没有遇到第三种选择?

由于这是一个主观问题,所以我不仅仅会喜欢“使用选项1”或“使用选项2”的答案,因此请尝试解释为什么您认为一种技术比另一种更好。甚至可以从您的经历中添加一两个故事,您已经看到了一种方法相对于另一种方法的好处。谢谢!

0 个答案:

没有答案