主持人注:这里已经有39个答案了(有些已经删除了)。在你发表你的答案之前,考虑一下你是否可以为讨论添加一些有意义的东西。你很可能只是在重复别人已经说过的话。
我偶尔发现自己需要将类中的私有方法设为public,只是为了为它编写一些单元测试。
通常这是因为该方法包含类中其他方法之间共享的逻辑,并且单独测试逻辑更整洁,或者另一个原因可能是我想测试同步线程中使用的逻辑,而不必担心线程问题。
其他人发现他们这样做是因为我不喜欢吗?我个人认为,公开一个方法的好处超过了它在类之外没有提供任何服务的问题……
更新
谢谢大家的回答,似乎引起了大家的兴趣。我认为普遍的共识是测试应该通过公共API进行,因为这是使用类的唯一方式,我非常同意这一点。在我上面提到的几个案例中,我会这样做,这是不常见的情况,我认为这样做的好处是值得的。
然而,我可以看到,每个人都指出它不应该真的发生。再仔细想想,我觉得改变你的代码来适应测试是一个坏主意——毕竟我认为测试在某种程度上是一个支持工具,而改变一个系统来“支持一个支持工具”是明显的坏做法。
正如其他人的评论所广泛指出的那样,单元测试应该关注公共API。然而,撇开利弊和论证不考虑,您可以通过使用反射在单元测试中调用私有方法。当然,您需要确保JRE安全性允许这样做。调用私有方法是Spring框架使用它的ReflectionUtils(参见makeAccessible(Method)方法)。
下面是一个带有私有实例方法的小示例类。
public class A {
private void doSomething() {
System.out.println("Doing something private.");
}
}
以及执行私有实例方法的示例类。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class B {
public static final void main(final String[] args) {
try {
Method doSomething = A.class.getDeclaredMethod("doSomething");
A o = new A();
//o.doSomething(); // Compile-time error!
doSomething.setAccessible(true); // If this is not done, you get an IllegalAccessException!
doSomething.invoke(o);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
执行B,将打印正在进行私有操作。如果确实需要,可以在单元测试中使用反射来访问私有实例方法。
更新:我已经在其他很多地方对这个问题增加了一个更广泛、更完整的答案。这可以在我的博客上找到。
如果我需要公开一些东西来测试它,这通常暗示被测试的系统没有遵循单一责任原则。因此,应该引入一个缺失的类。将代码提取到一个新类后,将其设为public。现在您可以轻松地进行测试,并且遵循SRP。您的其他类只需通过组合调用这个新类。
使方法公开/使用语言技巧,例如将代码标记为对测试程序集可见,应该始终是最后的手段。
例如:
public class SystemUnderTest
{
public void DoStuff()
{
// Blah
// Call Validate()
}
private void Validate()
{
// Several lines of complex code...
}
}
通过引入验证器对象重构此对象。
public class SystemUnderTest
{
public void DoStuff()
{
// Blah
validator.Invoke(..)
}
}
现在我们要做的就是测试验证器是否被正确调用。验证的实际过程(以前的私有逻辑)可以在完全隔离的情况下进行测试。不需要复杂的测试设置来确保验证通过。
最近,当重构一个大方法(> 200行)时,我也有同样的想法。对于每个逻辑步骤,我成功地将大方法拆分为较小的方法,因此很容易进行推理。
当涉及到重构出来的小型私有方法时,我想知道我是否应该单独测试它们,因为如果我只测试公共方法,我仍然在测试大方法,测试根本没有从重构中受益
经过一番思考,我意识到:
if all the small methods are private and can't be reused by others,
maybe I am doing something wrong: I am not pulling the right
abstraction from the code, I am only splitting the big methods
treating them like lines/strings, not like mental barrier
when I came to the right small methods(I refactored again,
completely changing the small methods), and move the small methods
into another class exposed as public methods for others to use,
now I can test them(and I should test them, they will be used more
and deserver the attention)
简介:
我仍然有很多小的私有方法,但是它们共享了很多公共方法,而且小方法真的很小(3-4行,主要是函数调用),但我不会测试它们,我只需要在另一个类中测试共享的公共方法