如何在Java应用程序中testing私有构造函数?

如果一个类包含一堆静态方法,为了确保没有人错误地初始化这个类的一个实例,我做了一个私有的构造函数:

private Utils() { } 

现在..鉴于构造函数不能被看到,怎么能testing呢? 这可以testing覆盖呢?

使用reflection,你可以调用一个私有的构造函数:

 Constructor<Util> c = Utils.class.getDeclaredConstructor(); c.setAccessible(true); Utils u = c.newInstance(); // Hello sailor 

但是,你甚至可以做到这一点是不可能的:

 private Utils() { throw new UnsupportedOperationException(); } 

通过在构造函数中抛出exception,可以防止所有的尝试。

我也会让课程本身也是final ,只是“因为”:

 public final class Utils { private Utils() { throw new UnsupportedOperationException(); } } 

testing代码的意图..总是:)

例如:如果构造函数的要点是不可见的,那么你需要testing的是这个事实,没有别的。

使用reflectionAPI查询构造函数并validation它们是否具有私有属性集。

我会做这样的事情:

 @Test() public void testPrivateConstructors() { final Constructor<?>[] constructors = Utils.class.getDeclaredConstructors(); for (Constructor<?> constructor : constructors) { assertTrue(Modifier.isPrivate(constructor.getModifiers())); } } 

如果你想对对象构造进行适当的testing,你应该testing公共API,它允许你获得构造的对象。 这就是所说的API应该存在的原因:正确地build立对象,所以你应该testing它:)。

 @Test public// void privateConstructorTest() throws Exception { final Constructor<?>[] constructors = Utils.class.getDeclaredConstructors(); // check that all constructors are 'private': for (final Constructor<?> constructor : constructors) { Assert.assertTrue(Modifier.isPrivate(constructor.getModifiers())); } // call the private constructor: constructors[0].setAccessible(true); constructors[0].newInstance((Object[]) null); } 

以确保没有人错误地初始化这个类的一个实例

通常我所做的是将方法/构造函数从私有方法更改为默认的包可见性。 而且我对testing类使用相同的包,所以从testing中可以访问方法/构造函数,即使它不是来自外部的。

为了执行策略,不要实例化类,您可以:

  1. 抛出UnsupportedOperationException(“不要实例化这个类!”)从默认的空构造函数。
  2. 声明类的抽象:如果它只包含静态方法,你可以调用静态方法但不实例化它,除非你inheritance它。

或者同时应用1 + 2,如果您的testing与目标类共享相同的包,您仍然可以inheritance子类并运行构造函数。 这应该是相当“错误的证据”; 恶意代码将总是find解决方法:)

如果你有一个私有的构造函数,它是从你的代码的一些不那么私有的方法调用的。 所以你testing这个方法,并且你的构造函数被覆盖了。 按照每种方法进行testing没有宗教美德。 你正在寻找function或更好的分支覆盖水平,你可以简单地通过使用它的代码path行使构造函数。

如果代码path复杂且难以testing,则可能需要重构它。

如果在构造函数中添加一个exception,例如:

 private Utils() { throw new UnsupportedOperationException(); } 

在testing类中constructor.newInstance()InvocationTargetException将会抛出一个InvocationTargetException而不是你的UnsupportedOperationExceptionexception,但是所需的exception将被包含在抛出的exception中。
如果要断言抛出exception,则可以在调用exception被捕获后抛出调用exception的目标。
例如,使用jUnit 4你可以这样做:

 @Test(expected = UnsupportedOperationException.class) public void utilityClassTest() throws NoSuchMethodException, IllegalAccessException, InstantiationException { final Constructor<Utils> constructor = Utils.class.getDeclaredConstructor(); constructor.setAccessible(true); try { constructor.newInstance(); } catch (InvocationTargetException e) { throw (UnsupportedOperationException) e.getTargetException(); } } 

别。 构造函数是私有的。 这就是你所需要的。 Java强制隐私。

不要testing平台。