我试图在工作组中倡导单元测试,但我经常遇到的反对意见是,它只能用于外部导出的API(这只是我们系统的最小和非关键部分),而不能用于内部和专用代码(现在仅具有功能测试)。
虽然我认为单元测试可以并且应该应用于所有代码,但是我如何说服我的同事?
我试图在工作组中倡导单元测试,但我经常遇到的反对意见是,它只能用于外部导出的API(这只是我们系统的最小和非关键部分),而不能用于内部和专用代码(现在仅具有功能测试)。
虽然我认为单元测试可以并且应该应用于所有代码,但是我如何说服我的同事?
Answers:
您的同事可能会将真实的单元测试与集成测试混淆。如果您的产品是(或具有)API,则可以将集成测试编程为NUnit测试用例。有些人错误地认为那是单元测试。
您可以尝试通过以下方式说服您的同事(我确定您已经知道这些知识,我只是想指出的是向您的同事指出可能会有所帮助):
在内部/私有代码上使用单元测试的原因与外部支持的API完全相同:
如果您按照我认为的意思来表示私密,那么不可以-不应该对它进行单元测试。您只能进行单元测试的可观察的行为/状态。您可能会错过TDD的“红绿重构”循环背后的要点(并且,如果您不先进行测试,则适用相同的原理)。编写测试并通过测试后,您不希望它们在执行重构时进行更改。如果您被迫对私有功能进行单元测试,则可能意味着围绕公共功能的单元测试存在缺陷。如果围绕公共代码编写测试既困难又复杂,那么您的类可能做得太多,或者您的问题没有明确定义。
更糟糕的是,随着时间的流逝,您的单元测试将变成一团糟,使您的速度降低,却丝毫不增加任何价值(更改实现,例如优化或删除重复项,对单元测试不会产生任何影响)。但是,应该对内部代码进行单元测试,因为行为/状态是可以观察到的(仅以受限的方式)。
当我第一次进行单元测试时,我花了各种各样的技巧对私有的东西进行单元测试,但是现在,在我的带领下,几年了,我认为这比浪费时间更糟糕。
这是一个愚蠢的例子,当然,在现实生活中,您将拥有比这些更多的测试:
假设您有一个返回字符串排序列表的类-您应该检查结果是否排序,而不是它对列表的实际排序方式。您可以使用仅对列表进行排序的单个算法来开始实施。完成后,如果您随后更改排序算法,则无需更改测试。此时,您只有一个测试(假设排序已嵌入您的类中):
现在说您想要两种算法(在某些情况下也许一种算法更有效,而在其他情况下则不是),那么每种算法都可以(并且通常应该)由不同的类提供,并且您的类从中选择—您可以检查这种情况是否正在发生您使用模拟程序选择的场景,但是您的原始测试仍然有效,并且由于我们仅验证可观察的行为/状态,因此无需更改。您最终进行了3个测试:
另一种选择是开始在您的类中测试私有代码-您从中什么也没有得到-上述测试告诉我就单元测试而言我需要知道的一切。通过添加私人测试,您可以为自己制造一件直筒外套,如果您不仅检查结果的排序方式,还检查结果的排序方式,会做多少工作?
(这种类型的)测试仅应在行为发生变化时才更改,开始针对私有代码编写测试,并且超出了测试范围。
人们很难接受单元测试,因为这似乎是浪费时间(“我们可能正在编写另一个赚钱的项目!”)或递归(“然后我们必须为测试用例编写测试用例!”)两者都说我很内gui。
第一次发现错误时,必须面对一个事实,即您并不完美(程序员很快忘记了它!),然后走了,“嗯”。
单元测试的另一个方面是必须将代码编写为可测试的。意识到某些代码很容易测试,而某些代码却不是一个好的程序员,所以他们会选择“嗯”。
您是否问过同事为什么单元测试仅对面向外部的API有用?
展示单元测试价值的一种方法是等待一个讨厌的错误发生,然后展示单元测试如何阻止它。这并不是要在他们的脸上摩擦它,而是要在他们的脑海中将单元测试从象牙塔理论转变为现实中的现实。
另一种方法是等到同一错误发生两次。“恩,老板,我们添加了代码以测试上周的问题后是否为空,但是这次用户输入的内容是空的!”
以身作则。为您的代码编写单元测试,然后向老板展示价值。然后看看老板是否有一天会叫披萨吃午餐并做一个介绍。
最后,我无法告诉您当我们要推向产品时所感到的缓解,并且单元测试中出现了一个绿色的条。
有两种类型的私有代码:私有代码被公共代码调用(或私有代码,获取由私人代码调用得到由公共代码(或...)调用)和专用代码,并没有最终会被公众称为码。
前者已经通过测试以测试公共代码。后者根本无法调用,因此应删除而不进行测试。
请注意,在执行TDD时,不可能存在未经测试的私人代码。
单元测试与测试代码单元有关。由您决定什么是单位。您的同事将单位定义为API元素。
无论如何,测试API也会导致行使私有代码。如果将代码覆盖率定义为单元测试进度的指标,则最终将测试所有代码。如果代码的某些部分尚未到达,请给您的同事三个选择: