处理TDD/单元测试疲劳

8
所以我正在逐渐习惯TDD,但我遇到了一个意外的问题:我对100%代码覆盖率感到非常疲倦。编写测试比编写代码本身更加乏味,而且我不确定自己是否做得正确。我的问题是:你应该测试哪些东西,哪些东西是过度的? 例如,我有一个测试如下,我不确定它是否有用。我应该怎么做才能遵循TDD,但不会因编写测试而感到疲倦?
describe 'PluginClass'

    describe '.init(id, type, channels, version, additionalInfo, functionSource, isStub)'

        it 'should return a Plugin object with correct fields'

            // Create test sets
            var testSets = new TestSets()
            var pluginData = {
                'id'                : null,
                'type'              : null,
                'channels'          : null,
                'version'           : null,
                'additionalInfo'    : null,
                'functionSource'    : null,
                'isStub'            : true
            }
            testSets.addSet({ 'pluginData' : pluginData })
            var pluginData = {
                'id'                : "testPlugin1",
                'type'              : "scanner",
                'channels'          : ['channelA', 'channelB'],
                'version'           : "1.0",
                'additionalInfo'    : {'test' : "testing"},
                'functionSource'    : "function () {alert('hi')}",
                'isStub'            : false
            }
            testSets.addSet({ 'pluginData' : pluginData })

            for (var t = 0; t < testSets.getSets().length; t ++) {
                var aTestSet = testSets.getSet(t)

                var plugin = new Plugin().init( aTestSet.pluginData.id,
                                                aTestSet.pluginData.type,
                                                aTestSet.pluginData.channels,
                                                aTestSet.pluginData.version,
                                                aTestSet.pluginData.additionalInfo,
                                                aTestSet.pluginData.functionSource,
                                                aTestSet.pluginData.isStub  )

                plugin.getID().should.eql aTestSet.pluginData.id
                plugin.getType().should.eql aTestSet.pluginData.type
                plugin.getChannels().should.eql aTestSet.pluginData.channels
                plugin.getVersion().should.eql aTestSet.pluginData.version
                plugin.getAdditionalInfo().should.eql aTestSet.pluginData.additionalInfo
                eval("fn = " + aTestSet.pluginData.functionSource)
                JSON.stringify(plugin.getFunction()).should.eql JSON.stringify(fn)
                plugin.getIsStub().should.eql aTestSet.pluginData.isStub
            }

        end

    end

end

在我看来,这是一个验收测试。 - Gutzofter
6个回答

7
当然,上述的“测试”在许多方面都过于冗长和复杂,几乎不可读,并且断言了太多东西。我几乎无法想象这是如何从TDD过程中出现的。毫不奇怪你会对这样的东西感到厌倦...
测试驱动开发意味着:你应该采取小步骤,每个步骤都是一个单独的测试,只断言一件事,并且不包含任何逻辑(即没有for、if/else或类似的...)。因此,上面的代码将导致大约4-6个单独的测试方法,然后您可以逐个实现它们。首先断言正确的属性初始化(使用所需的不同值),然后确保方法按预期工作,等等...
代码覆盖率指标除了可以显示未被任何测试触及的生产代码之外,不会告诉您有关测试的任何信息。特别是它不能告诉您触及的代码是否真正经过测试(而不仅仅是触及...)。这仅取决于您测试的质量。因此,不要太认真地考虑代码覆盖率,在许多情况下,具有更好测试的较低覆盖率更加可取...
总之: 对于几乎所有的东西都有测试(100%覆盖率)并不过分,但像您示例中的测试肯定是一个问题。
我建议您审查一下自己的TDD /单元测试实践,The Art Of Unit Testing这本书可能是一个很好的资源...
希望对您有所帮助! Thomas

推荐《单元测试的艺术》这本书,它提供了非常好的建议,是一本很棒的书。 - Bevan

4

有一件事情我认为人们经常忘记了,那就是自动化单元测试仍然是一种编码实践。你完全可以使用模板/通用类、基类、辅助类或者任何其他你熟悉的常规软件开发模式来进行单元测试。如果你觉得自己一遍又一遍地做同样的事情,那么你很可能是这样做的!这是你的大脑告诉你:“有更好的方法”的标志。

所以,去尝试吧。


1
非常正确。通常这是有问题的迹象。 - obelix

2
单元测试的目标应该是测试那些可能包含漏洞的代码部分。达到100%的测试覆盖率不应该成为一个目标,据我所知,TDD也没有将其作为目标。
对于不太可能包含重大漏洞的代码创建详尽的测试是一种繁琐的浪费时间的做法,无论现在还是在系统发展过程中都是如此。(未来,重复的单元测试很可能成为测试本身无意义的回归源,只会浪费某人的时间去发现和修复它们。)
最后,你和你的管理层在将某种开发方法应用于项目时应始终使用常识。任何已经发明的方法都不可能完全适用于所有问题/项目。你的工作之一就是发现方法在哪些情况下不起作用...如果必要,就要进行调整,甚至放弃它。在这种情况下,你/你的项目使用TDD的方式让你抓狂,这是一个明确的信号表明有些地方出了问题。

“100%的测试覆盖率... TDD并没有将其视为目标。”实际上,它确实是这样,在其宗教形式中,TDD要求在任何实际代码之前编写测试。否则,我同意。 - KolA

2

您的测试尝试一次性验证太多内容。将其拆分为多个测试,并重构测试代码(是的,允许使用辅助方法)。

此外,我觉得被测试的代码也做了太多事情。通过解耦您的代码(使用Extract Class和Extract Method等进行重构),并分别测试每个生产代码的部分。您会发现这些测试会变得更少,更简单,更容易阅读和编写。


0

疲劳、懒惰和冷漠是我们避免无意义工作的天性,例如编写琐碎的测试,这可能就是情况。试着停止对琐碎的东西进行单元测试,你应该会立刻感觉好些。

你特定的测试远非复杂。我参与过许多项目的代码审查,其中包括数千个单元和集成测试,但我还没有看到一个项目的测试比实际代码更易于阅读和理解。 TDD可读性,“测试即文档”等承诺根本不是真的。很容易证明-尝试通过仅阅读测试或仅阅读实际代码来学习新的代码库。哪种方式更全面? 正确设计的实际代码提供了组件的完整和全面的图片,而测试只是关于它的片段断言。

测试的唯一好处是自动化-对您的代码进行一些额外的验证,您不必手动执行/编译器或代码分析无法完成。时期。 而这个好处的代价很高-编写和维护测试,因此要谨慎选择要测试的内容。


0

看起来你正在测试构造函数与简单成员赋值。除非构造函数中有一些非平凡的逻辑,否则这是过度设计。相反,依靠其他测试来测试这个部分,其中成员将被使用。

  • 比较两个值对象之间的相等性。通过重写equals方法重新定义/定义插件类型/类上的相等性检查。所以plugin.should.eql expected_plugin应该是唯一的断言。
  • 还要考虑使用辅助对象来构建复杂的测试数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接