如何对严重依赖其他类的类进行单元测试?

Rya*_*Lue 5 ruby unit-testing rspec

我的理解是单元测试应该孤立地测试类,关注粒度行为并尽可能使用双精度/模拟替换其他类的对象。(如果我在这里错了,请纠正我。)

我正在写一个名为MatchList. MatchList::new接受两个参数,每个参数都是另一个名为 的类的实例MatchPhraseMatchPhrase包含一些MatchList严重依赖的行为(即,如果您提供除 a MatchPhraseto以外的任何内容MatchList::new,您将得到一堆“未定义方法”错误)。

我当前的(天真的?)测试设置使用let语句来分配变量以用于我的示例:

let(:query)      { MatchPhrase.new('Good Eats') }
let(:candidate)  { MatchPhrase.new('Good Grief') }
let(:match_list) { MatchList.new(query, candidate) }
Run Code Online (Sandbox Code Playgroud)

我如何编写这个单元测试?我认为它应该在不调用MatchPhrase类的情况下完成吗?这甚至可能吗?


作为参考,这里是MatchList类的样子:

class MatchList < Array
  attr_reader :query, :this_phrase, :that_phrase

  def initialize(query, candidate)
    super(query.length)
    @query = query
    @this_phrase = query.dup
    @that_phrase = candidate
    find_matches until none?(&:nil?)
  end

  private

  def find_matches
    query.each.with_index do |this_token, i|
      next unless self[i].nil?
      that_token = this_token.best_match_in(that_phrase)
      next if that_token.match?(that_token) &&
              this_token != that_token.best_match_in(this_phrase)
      self[i] = this_token.match?(that_token) ? that_token : NilToken.new
      this_phrase.delete_once(this_token)
      that_phrase.delete_once(that_token)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

fyl*_*ooi 1

嘲笑应该出于正当理由而不是作为原则问题进行。

如果只有一个协作者类,并且您的主类与其紧密耦合,则原则上模拟协作者可能会导致更多的脆弱性而不是好处,因为模拟不会反映协作者的行为。

当您可以针对模拟的接口而不是实现进行推理时,模拟和存根是很好的选择。让我们忽略现有的代码,看看这里使用的接口:

  • MatchList.new需要一个querycandidate
  • query是一个包含实现的对象的 Enumerablebest_match_in?(something)
  • 中的对象query还实现delete_once(something)
  • candidate还实现了delete_once(something)
  • best_match_in?返回实现match?best_match_in?

查看正在使用的接口,似乎非常依赖于和对象MatchList的实现。对我来说,这听起来像是一个令人羡慕的功能。也许这个功能应该驻留在其中。querycandidateMatchPhrase

在这种情况下,我将使用实际MatchPhrase对象编写单元测试,并附上重构此代码的注释。