所以我是一个相对较新的程序员,我还在学习,并遇到了一些问题(如果我的标签稍微偏离,那么道歉)。在早期,我有机会阅读一篇文章,讨论将包含大量代码的方法分解为许多较小的,明确命名的方法的调用的优点。总的来说,我觉得这样做的代码看起来更整洁,并且确保单元测试更容易。但是,我对是否将所有这些新方法公开或私有都有些担忧。将它们设为私有似乎是正确的做法,因为其余的代码通常不需要访问这些方法。但是,单元测试私有方法可能会很混乱。这是最好的做法吗?
我现在在做什么:
public class WashingMachine {
public Load wash(Load load) {
// Removes one sock from load
for (ClothingItem item : load.getItems()) {
if (item.getType().equalsIgnoreCase("sock") {
load.removeItem(item);
.. // logic for sending sock to proper dimension
break;
}
}
// rest of logic for cleaning clothes
}
}
变成:
public class WashingMachine {
// Wash a load of laundry
public Load wash(Load load) {
// Removes one sock from load
removeSock(load.getItems());
// rest of logic for cleaning clothes
..
}
// Oh no, I can't unit test this easily!
private void removeSock(List<ClothingItem> items) {
...
}
}
答案 0 :(得分:5)
将您的公共方法视为您希望允许任何人使用的功能。
这些功能中的一些可能很复杂,而且你是对的,该功能应该分成不同的方法。问题是,“他们有什么样的访问权限?”
好吧,如果它们是公开的,现在外部类可以访问您真正不需要的内部功能。即使它不会破坏任何东西,当你开始处理大型项目(拥有更大的团队)时,通过公开它,其他程序员可能会使用该功能,这现在阻止你改变它。
例如,以汽车类比。假设您的方法是accelerate()
。这可能会调用releaseGas()
。但是,您不希望任何人在外部释放气体。它只应在受控环境中调用。
然后是受保护的访问权限。受保护的访问权限适用于可以通过扩展类来覆盖的方法。这些应该是执行与内部功能相关的特定工作块的方法。再次以汽车为例,可能会有使用特殊类型气体的RaceCar clas,因此它希望提供自己的释放气体的方法。这是releaseGas
受保护的原因。
至于测试,你应该主要测试你的公共合同。这是其他课程使用的,最后,这才是真正重要的。您的内部方法是您的功能的内部方法,将通过测试您的公共合同进行测试。这也意味着您的类应首先根据其外部用途进行设计,并围绕该类进行测试。 (即使采用测试驱动的开发,随着您获得经验,这也会变得更容易。)
当然,有时这些内部方法足够复杂,他们需要自己进行单元测试。但是,您不需要对它们进行保护。在这种情况下,您可以将它们设为默认访问权限。 (既不公开也不受保护)。只要您的单元测试在同一个包中,您就可以调用它们。
更好的是,如果您知道您不希望任何人扩展它,但您需要对其进行测试,请将其设为protected final
或仅final
。这仍然允许调用它,但至少可以防止它被覆盖。
编辑:
Ryan的评论如下。如果你的类变得足够复杂,需要测试它的内部方法,那么它们应该被提取到它们自己的类中,然后可以独立地进行单元测试。
总的来说,您的测试应该是测试您单独单位的公共合同。
答案 1 :(得分:1)
我认为你应该根据将要调用它的(主要的,不是测试的)代码来设计你的类。如果没有人需要拨打WashingMachine.removeSock()
,我会留下private
。
对于单元测试,确定这意味着你无法在WashingMachine
内测试这一个单独的逻辑 - 但你仍然可以测试wash()
方法,如果这就是使用WashingMachine
的其他组件可见,您真正需要关注的是测试。
可以编写太粒度的单元测试并关注细节。