鲍勃叔叔说:
“非公共API中的防御性编程是不做TDD的团队的一种气味,也是一种症状。”
我想知道TDD如何避免以意外的方式使用(内部)函数?我认为TDD是无法避免的。它仅仅显示了该函数的正确使用,因为调用函数包含在其通过的单元测试中。
在使用(非防御性的)函数开发新特性时,也使用TDD进行开发。因此,该函数的意外使用将无法通过新的功能测试。
因此,使用TDD来驱动新功能将迫使您正确地使用(内部)功能。
你认为鲍勃叔叔的推特是什么意思?
发布于 2017-08-22 09:08:38
因此,使用TDD来驱动新功能将迫使您正确地使用(内部)功能。
一点儿没错。但是,请记住这里的细微“空白”:您应该使用TDD编写(单元)测试contract的公共方法。您并不关心这些方法的实现--这是所有内部实现的细节。
因此:如果您的“新”代码以一种意外的方式使用现有的方法,您就会“被告知”,因为抛出了一个异常,或者您收到了一个意外的结果。
这就是我所说的“差距”:你看,上面描述了一种黑匣子测试方法。您有一个公共方法X,并验证它的公共契约。与白盒测试相比,您编写的测试涵盖了X中的所有路径。当这样做时,您可能会注意到:“好的,要测试我的内部方法中的一个条件,我将不得不驱动这些特殊数据”。
但是如前所述--我认为您应该进行黑匣子测试--在重构内部方法时,白盒测试可能很容易崩溃。
这里还有一个额外的维度:请记住,理想情况下,更改代码以实现新特性。这意味着添加新特性只能通过编写新的类和方法来实现。这意味着您的新代码没有机会使用私有内部方法。因为你在一个新的班级里。换句话说:当您经常遇到以许多不同方式使用内部方法的情况时--那么您可能做了一些错误的。
理想的途径是:通过创建一组新的类来实现新的需求。稍后,您必须添加其他要求-通过编写更多的类。
在这种理想的路径中--在内部方法中不需要需要来进行防御性编程。因为您完全理解这种内部方法的每个用例!
因此,结论是:避免在内部方法中进行防御性规划。确保您的公共API检查所有的预条件,这样如果出现问题,它们就会失败(尽可能快)。尽量避免这些内部一致性检查--因为它们会使你的代码膨胀--并且请放心:在5个星期或5个月内,你将不记得你是否真的需要检查,或者它是否只是“防御性的”。
发布于 2017-08-22 13:40:49
回答这个问题的一种方法是看看鲍勃叔叔在这个话题上还说了些什么。例如
在一个代码覆盖率低、测试少、遗留代码混乱的系统中,防御性编程应该是一条规则。 在一个由TDD产生的系统中,具有90+%覆盖和高度可靠、维护良好的单元测试,防御性编程应该是例外。
从这一点,我们可以推断出他的主要论点--如果防御性检查实际上提供了一个好处,那就是暗示我们缺少了一些约束。如果我们缺少一些约束,并且所有的测试都通过了,那么我们也必须缺少一些测试。
或者,用一种稍微不同的方式来表达相同的想法--您的实现中的防御模式所隐含的约束应该更接近边界(即在公共API中)。
例如,如果存在限制,以限制允许哪些数据通过边界,则应该进行测试,以确保边界实际上实现了这些约束。
发布于 2017-08-21 13:13:35
当您正确地使用TDD时,您将涵盖所有可能的情况,并断言您调用私有函数的公共函数确实按照预期正确地响应,不仅是对于愉快的场景,而且对于所有不同的可能场景。当您在您的私有方法中使用保护程序时,实际上您正在为上述这些(不同的可能)场景做好准备。
就我个人而言,我并不认为维护编程是有害的,即使是在私有方法中,然而,根据我上面的描述,我认为这是一种不必要的双重努力,而且它消除了TTD的重要性,因为您正在处理应用程序中的这些特殊情况,使代码复杂化,而不是以一种证明的方式编写它。
https://stackoverflow.com/questions/45797879
复制相似问题