在TDD开发中,您通常首先要创建接口,然后开始针对该接口编写单元测试.当您逐步完成TDD过程时,您最终会创建一个实现接口的类,然后在某些时候您的单元测试将通过.
现在我的问题是关于我可能必须在我的类中编写的私有和受保护的方法,以支持接口公开的方法/属性:
班级中的私有方法是否应该有自己的单元测试?
班级中受保护的方法是否应该有自己的单元测试?
我的想法:
特别是因为我正在编写接口,我不应该担心受保护/私有方法,因为它们是黑盒子.
因为我正在使用接口,所以我正在编写单元测试以验证定义的合同是否由实现接口的不同类正确实现,所以我再也不担心私有/受保护的方法,并且应该通过调用它的单元测试来执行它们.接口定义的方法/属性.
如果我的代码覆盖率没有显示受保护/私有方法被命中,那么我没有正确的单元测试,或者我有没有被使用的代码,应该被删除.
小智 102
不,我不认为测试私有或受保护的方法.类的私有和受保护方法不是公共接口的一部分,因此它们不会暴露公共行为.通常,这些方法是在您将测试变为绿色后通过重构创建的.
因此,这些私有方法由断言公共接口行为的测试隐式测试.
在更哲学的说明中,请记住,您正在测试行为,而不是方法.因此,如果您考虑被测试类可以执行的操作集,只要您可以测试并断言该类的行为与预期一致,是否存在由类在内部使用的私有(和受保护)方法来实现这种行为无关紧要.这些方法是公共行为的实现细节.
Cha*_*oth 41
我不赞同大多数海报.
最重要的规则是:工作代码启动关于公共/受保护/私人的理论规则.
您的代码应该经过全面测试.如果你可以通过为公共方法编写测试来实现这一点,那么就可以充分运用受保护/私有方法,这很好.
如果你不能,那么要么重构,要么你可以,或弯曲受保护/私人规则.
关于给孩子们进行测试的心理学家,有一个很棒的故事.他给每个孩子两块木板,两端各有一根绳子,要求他们尽可能快地穿过房间,不要将脚碰到地板.所有的孩子都使用小板滑雪板,每块板子一只脚,用绳子抓住它们,然后滑过地板.然后他给了他们同样的任务,但只使用了一块板.他们在地板上转动/"走",一只脚踏在单板的每一端 - 而且它们更快!
仅仅因为Java(或任何语言)具有一个功能(私有/受保护/公共)并不一定意味着您正在编写更好的代码,因为您使用它!
现在,总会有方法来优化/最小化这种冲突.在大多数语言中,您可以使方法受到保护(而不是公共),并将测试类放在同一个包(或其他)中,并且该方法可用于测试.正如其他海报所描述的那样,有一些注释可以提供帮助.您可以使用反射来获取私有方法(yuck).
背景也很重要.如果您正在编写供外部人员使用的API,则公共/私有更重要.如果这是一个内部项目 - 谁真的关心?
但最终,请考虑缺少测试导致的错误数量.然后比较"过度可见"方法导致的错误数量.那个答案应该会推动你的决定.
Lun*_*ore 34
你写了:
在TDD开发中,您通常首先要创建接口,然后开始针对该接口编写单元测试.当您逐步完成TDD过程时,您最终会创建一个实现接口的类,然后在某些时候您的单元测试将通过.
请让我用BDD语言改写一下:
在描述类为什么有价值以及它的行为方式时,通常首先要创建一个如何使用类的示例,通常是通过其接口*.当您添加所需的行为时,您最终会创建一个提供该值的类,然后在某些时候您的示例可以正常工作.
*可能是类的实际
Interface
或简单的可访问API,例如:Ruby没有接口.
这就是为什么你不测试私有方法 - 因为测试是如何使用类的一个例子,你实际上不能使用它们.如果你愿意,你可以做的事情是将私有方法中的职责委托给协作类,然后模拟/存储帮助程序.
使用受保护的方法,您会说扩展类的类应该具有某些特定的行为并提供一些值.然后,您可以使用类的扩展来演示该行为.例如,如果您正在编写有序集合类,则可能需要演示具有相同内容的两个扩展是否相等.
希望这可以帮助!
for*_*rir 15
当您为类编写单元测试时,您不必关心类的功能是否直接在公共接口上的方法中实现,或者是否在一系列私有方法中实现.所以是的,您应该测试您的私有方法,但是您不需要直接从您的测试代码中调用它们(直接测试私有方法将您的实现紧密地耦合到您的测试并使重构变得不必要).
受保护的方法在您的类和未来的子级之间形成不同的契约,因此您应该在与公共接口类似的程度上对其进行测试,以确保合同得到很好的定义和运用.
完成上面其他人所说的,我会说受保护的方法是某种接口的一部分:它恰好是暴露于继承而不是组合的接口,这是每个人在考虑接口时都会考虑的问题.
将方法标记为受保护而非私有意味着它应该被第三方代码使用,因此需要定义和测试某种契约,就像公共方法定义的普通接口一样,这些接口对于继承和组合都是开放的. .
编写测试有两个原因:
承担(1)断言预期的行为:
当您声明预期的行为时,您希望确保代码按照您的想法运行.这实际上是一种自动执行常规手动验证的方式,任何开发人员在实现任何类型的代码时都会执行此操作:
这些是我们在脑海中回答的问题,通常,我们也会尝试在头脑中执行代码,确保它看起来确实有效.对于这些情况,让计算机以明确的方式回答它们通常很有用.所以我们编写一个断言它的单元测试.这使我们对代码充满信心,帮助我们尽早发现缺陷,甚至可以帮助实际实现代码.
在您觉得有必要的地方这样做是个好主意.任何有点难以理解或非常重要的代码.即使是微不足道的代码也可以从中受益.这完全取决于你自己的信心.多久做一次以及走多远取决于你自己的满意度.当你可以自信地回答"是"时停止:你确定这有效吗?
对于这种测试,您不关心可见性,接口或其中任何一种,您只关心工作代码.所以,是的,如果您认为需要对您进行测试以回答问题,那么您将测试私有和受保护的方法.
采取行动(2)防止行为回归:
一旦你有了工作代码,你需要有一个机制来保护这些代码免受未来的破坏.如果没有人再次触摸你的源和你的配置,你就不需要这样,但在大多数情况下,你或其他人会触及你的软件的来源和配置.这种内部摆弄极有可能破坏您的工作代码.
大多数语言中都存在机制,以防止这种损害.可见性功能是一种机制.私有方法被隔离并隐藏.封装是另一种机制,您可以在其中划分内容,以便更改其他隔离专区不会影响其他隔离专区.
这种方法的一般机制称为:编码到边界.通过在代码的各个部分之间创建边界,可以保护边界内的所有内容不受其外部内容的影响.边界成为交互点,以及事物相互作用的契约.
这意味着通过打破界面或破坏它的预期行为来改变边界会损坏并可能破坏依赖它的其他边界.这就是为什么进行单元测试是一个好主意,它针对这些边界并断言它们不会在语义和行为上发生变化.
这是您典型的单元测试,在提及TDD或BDD时,每个人都会讨论这个问题.重点是加强边界并保护它们免受变化.您不希望为此测试私有方法,因为私有方法不是边界.受保护的方法是限制边界,我会保护它们.它们不暴露于世界,但仍暴露于其他隔间或"单位".
该怎么做?
正如我们所见,有一个很好的理由对单元测试公共和受保护的方法进行单元测试,因为断言我们的接口不会改变.并且还有充分的理由来测试私有方法,以断言我们的实现工作.那么我们应该对它们进行单元测试吗
是和否.
首先:测试所有您认为需要明确证明其在大多数情况下有效的方法,以便能够确信您的代码能够工作,无论可见性如何.然后,禁用这些测试.他们已经完成了工作.
最后:为您的边界编写测试.对系统其他单元使用的每个点进行单元测试.确保此测试断言语义契约,方法名称,参数数量等.还要确保测试断言单元的可用行为.您的测试应该演示如何使用该装置,以及该装置可以做什么.保持这些测试的启用,以便它们在每次代码推送时运行.
注意:您禁用第一组测试的原因是允许重构工作发生.主动测试是代码耦合.它可以防止将来修改它正在测试的代码.您只希望这适用于您的接口和交互合同.