1
92
你提出的第一个问题是所谓的“脆弱测试”问题。您对应用程序进行了更改,数百个测试因该更改而中断。当这种情况发生时,你有一个 设计 问题。你的测试设计得很脆弱。它们还没有与生产代码充分分离。解决方案是(就像在所有这样的软件问题中一样)找到一个抽象,它将测试与生产代码分离,从而使生产代码的波动性隐藏在测试中。 导致这种脆弱性的一些简单因素是:
测试设计是TDD初学者经常忽视的一个重要问题。这通常会导致脆弱的测试,然后导致新手将TDD视为“非生产性”而拒绝。 你提出的第二个问题是误报。您使用了如此多的模拟,以至于没有一个测试真正测试集成系统。虽然测试独立单元是一件好事,但测试系统的部分和全部集成也很重要。TDD是 不 关于单元测试。 试验安排如下:
|
2
12
最好是修复由于有意的代码更改而失败的单元测试,而不是不进行测试来捕获这些更改最终引入的错误。 当您的代码库具有良好的单元测试覆盖率时,您可能会遇到许多单元测试失败,这些失败不是由于代码中的错误,而是由于合同或代码重构的有意更改造成的。 但是,这种单元测试覆盖率还将使您有信心重构代码并实现任何合同更改。有些测试将失败,需要修复,但其他测试最终将失败,因为您在这些更改中引入了错误。 |
3
5
单元测试当然不能捕获所有的错误,即使在100%代码/功能覆盖的理想情况下也是如此。我认为这是意料之中的。 如果测试的合同发生变化,我(开发人员)应该用我的大脑更新所有代码(包括测试代码!)因此。如果我未能更新一些因此仍然产生旧行为的模拟,那是我的错误,而不是单元测试。 这与我修复bug并为其生成单元测试时的情况类似,但我没有仔细考虑(并测试)所有类似的情况,其中一些情况后来也被证明是错误的。 所以是的,单元测试和生产代码本身一样需要维护。没有维护,它们就会腐烂腐烂。 |
4
4
我在单元测试方面也有类似的经验——当你经常改变一个类的契约时,你也需要改变其他测试的负载(在很多情况下,这实际上会通过,这使得它更加困难)。这就是为什么我总是使用更高级别的测试:
请注意,即使您有100%的单元测试覆盖率,您甚至不能保证您的应用程序启动!这就是为什么你需要更高级别的测试。有这么多不同的测试层,因为您测试的东西越低,它通常就越便宜(在开发、维护测试基础设施以及执行时间方面)。 另一个注意事项是——由于您提到的使用单元测试的问题教您尽可能地保持组件的分离和它们的契约尽可能小——这绝对是一个很好的实践! |
5
3
有人问了同样的问题 Google Group 为书“成长面向对象软件-由测试指导”。线程是 Unit-test mock/stub assumptions rots . 这里是 J.B. Rainsberger's answer (他是曼宁的作者) JUnit食谱 “”。 |
6
2
单元测试代码(以及用于测试的所有其他代码)的规则之一是将其与生产代码(不多也不少)一样对待。 我对这一点的理解是(除了保持它的相关性、重构、工作等,如生产代码),还应该从投资/成本的角度来看待它。 也许您的测试策略应该包括一些东西来解决您在最初的帖子中描述的问题——一些沿着行的东西,指定当设计人员更改生产代码中的函数/方法时,应该审查(执行、检查、修改、修复等)哪些测试代码(包括存根/模拟)。因此,任何生产代码更改的成本必须包括这样做的成本-如果不是-测试代码将成为“三等公民”,设计人员对单元测试套件的信心及其相关性将降低…显然,投资回报率是在错误发现和修复的时机。 |
7
1
我在这里依赖的一个原则是消除重复。我通常没有很多不同的假货或模仿履行这个合同(我使用更多的假货比模仿部分原因)。当我更改合同时,自然会检查该合同、生产代码或测试的每个实现。当我发现我正在做这种改变的时候,我的抽象可能已经被更好地考虑了等等,但是如果测试代码对于合同变更的规模来说太过繁重而无法改变,那么我必须问自己这些是否也是由于某种重构造成的。 |
8
0
我是这样看的,当你的合同变更时,你应该像对待新合同一样对待它。因此,您应该为这个“新”契约创建一套全新的单元测试。事实上,您已经有了一组现有的测试用例。 |
9
0
我认为问题出在设计上。我还要后退一步 检查合同的设计 . 简而言之
而不是说“X==0时返回-1”或“X==Y时引发无法计算异常”,
欠详细说明
适当情况下的非特定化您可以根据以下条件区分您的语句“-1,当它由于某种原因失败时”:是场景吗?
如果且仅当1)至3)保持,则在合同中指定方案(例如
如果没有1),实现就不能保证特殊情况下的特定行为。例如,当不满足反身性、对称性、传递性和一致性条件时,object.equals()不指定任何行为。
如果没有2),则不满足单一责任原则,模块性被破坏,代码的用户/读者会感到困惑。例如,
如果没有3,则调用方无法使用指定的行为(某些返回值/异常)。例如,如果JVM抛出一个未知错误。 利弊如果您指定了1)、2)或3)不适用的情况,则会遇到一些困难:
非特定化的缺点是(测试)健壮性,即实现对异常情况做出适当反应的能力,更加困难。 作为折衷方案,我喜欢尽可能使用以下合同模式:
|
mg610 · 如何开始C++单元测试 2 年前 |
Phil Gunning · 使用嵌套函数更改进行模拟测试 2 年前 |
shilin agre · 在Python中测试修饰函数 2 年前 |
SlipScout · Unittest只传递单个值,而不是获取多个值 2 年前 |
Alex · 从实际对象的实例返回默认模拟结果 2 年前 |