如何通过示例避免过度测试

时间:2013-05-01 04:24:01

标签: unit-testing testing rspec tdd

我一直在尝试更多地开始测试我的代码,我想我会模仿我自动生成的一些测试的样式(我使用的是rspec和rails,但我的问题确实是只是general-tdd)。然而,这些方法非常基础,就像做某事一样。然后,如果foo,做其他事情。我觉得,一旦你变得更加复杂,你可以在你的if中添加另外两件东西,事情就会开始螺旋式上升,你会得到遍布各地的嵌套例子。这是我一直在做的事情的一个例子,感觉有点矫枉过正。

首先是方法

def maybe_blah(foo)
  if foo != nil && foos.find_by_id(foo.id) != nil
    blah unless bar?(foo)
  end
end

这种方法很简单,这就是我计划测试的方法

describe maybe_blah

  shared_examples "what happens when bad input is passed" do
    it "doesn't call bar?"...
    it "doesn't call blah"...
  end

  context "when foo is not nil"
    context "when foo is in foos"
      context "bar? returns true"
        it "doesn't call blah" do
           some code involving mocking bar? and blah 
        end
      end

      context "bar? returns false"
        it "does call blah" do
           some code involving mocking bar? and blah 
        end
      end
    end

    context "when foo is not in foos"
       include_examples "what happens when bad input is passed"
    end
  end

  context "when foo is nil"
     include_examples "what happens when bad input is passed"
  end
end

如果有所有的设置和其他任何东西(测试也许是真实的,就像那个花了我55行),这明显比测试的短,所以你可以看到它似乎失控。有没有一种很好的方法来测试一种确实有这种矫枉过正的方法。

当你测试3个条件时(至少没有重复自己更多),我没有看到3-deep嵌套的方法,但似乎你需要这样做才能确保你'处理所有不同的情况。此外,对于每个不同的错误输入测试失败结果似乎是愚蠢的,但是你怎么知道你实际上在那些糟糕的输入上失败?

这只是矫枉过正吗?

1 个答案:

答案 0 :(得分:1)

实际上你的条件与:

相同
def maybe_blah(foo)
  if foo != nil && foos.find_by_id(foo.id) != nil && !bar?(foo)
    blah
  end
end

因此,您可以使用Decompose ConditionalConsolidate Conditional Expression技术将其提取为单独的方法:

def maybe_blah(foo)
  blah if can_do_it?(foo)
end

def can_do_it?(foo)
  foo != nil && foos.find_by_id(foo.id) != nil && !bar?(foo)
end

之后,您可以在两个contexts

中测试此方法
describe '#maybe_blah' do
  context 'when can do' do
    # stub can_do_it? and returns true
    # stould receive :blah
  end

  context 'when cant do' do
    # stub can_do_it? and returns false
    # should not receive :blah
  end
end

分别测试条件。

您可以省略!= nil

def can_do_it?(foo)
  foo && foos.find_by_id(foo.id) && !bar?(foo)
end