添加返回对象内部状态的函数进行单元测试是否更好,而不是让测试类成为朋友? - 尤其是当除了单元测试的情况之外没有用于功能时。
答案 0 :(得分:12)
单元测试应该有95%的时间只测试一个公开暴露的类表面。如果您正在测试一些内容,那就是测试实现细节,这本身就很脆弱,因为您应该能够轻松地更改实现并仍然可以使测试工作。它不仅易碎,而且还可能会尝试测试在计划使用场景中实际无法实现的事情,这是浪费时间。
如果要添加的访问器的目的只是为了测试函数是否具有所需的效果,那么您的类设计可能会违反另一个原则,即类似状态机的类应始终明确说明哪个状态如果这会影响人们与班级互动时发生的事情。在这种情况下,提供那些只读访问器是正确的。如果它不影响类的行为,请参考我之前关于实现细节的内容。
正如你正确地说的那样,由于其自身原因,使用未使用过的东西弄乱一个班级的公共表面也是不可取的。
如果我 在你的案例中选择访问者和朋友,我会选择朋友,只是因为你拥有你的测试并且可以在紧要关头改变它。您可能没有找到使用额外存取器的小丑的代码,然后您将被卡住。
答案 1 :(得分:9)
我不同意接受的答案,而是建议使用朋友班。
您正在测试的部分州可能特定于您班级的实施;您正在测试其他代码通常不了解或不关心的细节,也不应该依赖。公共访问器函数使这些实现细节成为类接口的一部分。如果您正在测试的内部状态不是预期接口的一部分,则不应通过公共功能看到它。从纯粹主义的角度来看,你被困在两个错误的答案之间,因为朋友类在技术上也是公共界面的一部分。在我看来,问题就变成了,哪种选择不太可能导致糟糕的编码选择?使用一组依赖于实现的公共访问器函数将无意中鼓励依赖于实现的类的概念模型,从而导致依赖于实现的类的使用。一个适当命名和记录的单个朋友类不太可能被滥用。
虽然总的来说我非常赞同更喜欢访问者函数而不是直接访问成员变量的建议,但我不同意这种最佳实践适用于依赖于实现的内部状态的单元测试。合理的中间立场是将私有访问器功能用于您的单元测试所关注的那些状态,并且足够严格以在单元测试中使用访问器功能。只是我的意见。
答案 2 :(得分:3)
使用友元类进行单元测试是完全合法的,并允许您维护封装。您不应该简单地修改类的公共接口,以使类更易于测试。这样想吧。如果您购买了第三方FTP库并且您正在尝试使用它并且它的公共界面混乱了一堆您甚至不需要知道的单独测试方法,那该怎么办呢!甚至修改受保护的接口以补偿单元测试也是不好的。如果我从某个类继承,我不想担心哪些方法对我有用,哪些方法只是因为单元测试!使用朋友类进行单元测试可以帮助您维护一个简单易用的类接口;它有助于保持封装和抽象!
我听说过使用友元类进行单元测试是不好的,因为被测试的类不应该与其测试类“紧密耦合”,并且它不应该“知道”有关其测试类的任何内容。我不买这个。它是添加到班级顶层的单行:
朋友类MyClassTest;
现在你可以按照自己想要的方式测试你的课程!
现在我同意你不应该使用朋友班,除非有必要。如果你可以测试什么需要测试而不是让它成为朋友,那么一定要做。但是如果生活变得困难并且使用朋友班让生活变得轻松,那就使用它吧!
答案 3 :(得分:1)
我建议使用访问者,而不是允许通过公共成员或朋友类进行访问。
我认为使用朋友课实际上并没有给你带来任何好处,而且它有可能让你的生活更加艰难。如果你的代码会长时间存在,很有可能它会以你预期的方式使用。访问功能现在可能只用于测试,但是谁知道将来会发生什么?使用访问器而不是直接访问变量可以提供更大的灵活性,而且成本非常低。
另一个论点是使用访问者而不是公共成员是一个好习惯。养成良好的习惯是程序员的一项重要技能。
答案 4 :(得分:0)
如何让内部状态“受到保护”? 然后使用派生类进行unittest。
答案 5 :(得分:0)
我认为,如果有意义的话,通过为用户提供访问器以及提高可测试性,需要区分未来的类。我也不是为了测试的唯一目的而与朋友进行交流的忠实粉丝,因为这会在我不喜欢它的地方引入紧密耦合。
如果唯一使用访问器是为测试用例提供检查类的内部状态的方法,那么公开公开它们通常没有意义。它还可以绑定您可能希望稍后更改的实现细节,但后来发现您不能,因为其他人正在使用所述访问器。
我首选的解决方案是提供受保护的访问者函数,以便清楚地向类的用户传达这些不属于公共接口的用户。然后,您的测试将创建原始的最小派生类,其中包含父级函数的调用存根,但也会使访问者公开,以便您可以在测试用例中使用它们。