Php TDD与封装优先级冲突

Php TDD与封装优先级冲突,php,unit-testing,tdd,phpunit,encapsulation,Php,Unit Testing,Tdd,Phpunit,Encapsulation,我刚开始在我的项目中练习TDD。我现在正在开发一个项目,使用php/zend/mysql和phpunit/dbunit进行测试。我只是对封装和测试驱动方法的想法有点分心。封装背后的想法是隐藏对多个对象功能的访问。更清楚地说,私有函数和受保护函数是不可直接测试的(除非您将创建一个公共函数来调用它) 因此,我最终将一些私有和受保护的函数转换为公共函数,以便能够测试它们。我真的违反了封装的原则,让位于微功能的可测试性。这是正确的做法吗 在TDD圈子里有一个非常标准的答案。如果一个类中有您都希望隐藏并直

我刚开始在我的项目中练习TDD。我现在正在开发一个项目,使用php/zend/mysql和phpunit/dbunit进行测试。我只是对封装和测试驱动方法的想法有点分心。封装背后的想法是隐藏对多个对象功能的访问。更清楚地说,私有函数和受保护函数是不可直接测试的(除非您将创建一个公共函数来调用它)


因此,我最终将一些私有和受保护的函数转换为公共函数,以便能够测试它们。我真的违反了封装的原则,让位于微功能的可测试性。这是正确的做法吗

在TDD圈子里有一个非常标准的答案。如果一个类中有您都希望隐藏并直接测试的功能,您应该使用该功能。这是TDD如何改进设计的一个很好的例子


在原始类中,无关的功能消失了,包装在萌芽类中,因此原始类的设计更简单,并且更好地符合标准。在萌芽类中,提取的函数是它的ReunyDeTrE,因此它是合适的公开的,因此它是可测试的而不需要测试的修改。

< P>关于Carl Manaster的好答案,在开始CARL建议的路径之前,你应该至少考虑一些缺点。 其中最重要的一点是:我们使用封装来最小化潜在依赖的数量,这些依赖具有最大的变化传播概率。在您的例子中,您已经在类中封装了私有方法:它们对其他类不可用,因此对它们没有潜在的依赖关系:您对它们所做的任何更改的成本都是最小的,并且传播到其他类的可能性很低

Carl似乎建议将一些私有方法从类移动到新类中,并将这些方法公开(以便您可以测试它们)。(顺便提一下,为什么不在原来的课堂上公开呢?)

通过这样做,您消除了其他类对这些方法形成依赖关系的障碍,这可能会增加任何其他类使用这些方法时更改这些方法的成本

您可能会认为这是一个不利的次要因素,并且是一个值得为能够测试您的私有方法而付出的代价,但至少要意识到这一点。在少数情况下,这可能确实是值得的,但如果您在整个代码库中都这样做,那么您将极大地增加这些依赖关系形成的可能性,从而将维护周期的成本增加到未知的程度

基于这些原因,我不同意Carl的观点,他认为“TDD是如何改进设计的一个很好的例子。”

此外,他指出,“在原始类中,无关的功能消失了,包装在萌芽类中,因此原始类的设计更简单,更符合单一责任原则。”

我认为,正在移动的功能根本不是“无关的”。此外,“更简单”是一个定义不明确的概念:一个类的简单性当然可能与其大小成反比,但这并不意味着一个由最简单的类组成的系统将是最简单的系统:如果是这样的话,所有类只包含一个方法,一个系统将有大量的类;可以说,删除类中多个方法的分层结构将使系统更加复杂

此外,单一责任原则(SRP)是出了名的主观原则,完全取决于观察者的抽象程度。从类中删除一个方法会自动提高它与SRP的一致性,这一点完全不是这样。一个包含10个方法的Printer类在类的抽象级别上负责打印。其方法之一可能是CheckPrinterConnection(),另一个可能是checkPaper();在方法级别,这些显然是独立的职责,但它们并不自动建议将类分解为更多的类

Carl最后说,“在萌芽类中,提取的功能是其存在的理由,因此它适合于公开,因此它可以在不进行仅测试修改的情况下进行测试。”功能的重要性(存在的理由)并不是其公开的适当性的基础。功能公开的适当性的基础是最小化向客户机公开的接口,以便在最大限度地提高客户机对功能实现的独立性的同时,类的功能可供使用。当然,如果只将一个方法移动到萌芽类中,那么它必须是公共的。但是,如果要移动多个方法,则必须将那些对客户机成功使用类至关重要的方法公开:这些公开方法可能远不如您希望保护客户机的某些私有方法重要。(在任何情况下,我都不喜欢“存在的理由”这个短语,因为方法的重要性也没有很好的定义。)

Carl建议的另一种方法取决于您设想的系统增长规模。如果它将增长到少于几千个类,那么您可能会考虑使用一个脚本将源代码复制到一个新目录中,在复制的源中更改“私有”到“公共”的所有事件,然后对复制的源编写测试。这会减少复制代码所需的时间,但也有保留原始源代码封装的好处,同时使所有方法都可以在复制的源代码中进行测试
sed -i 's/private/public/g' $i