JUnit:仅包含静态方法的测试辅助类

11 浏览
0 Comments

JUnit:仅包含静态方法的测试辅助类

我正在使用JUnit4和Cobertura测试一个只有静态方法的帮助类。测试方法已经完成了。

然而,Cobertura显示,由于没有在任何地方实例化该类,因此测试没有完全覆盖该类。

我不想创建这个类的实例(它是一个帮助类),所以第一个解决方案是隐藏构造函数(这通常是一个很好的办法,适用于帮助类)。

然后,Cobertura会抱怨空的私有构造函数没有被测试覆盖。

有没有解决方案可以实现这种情况的100%代码覆盖率?

在这种情况下,需要从高层管理层面要求代码覆盖率,因此对我来说,获得这个特定类的100%非常有帮助。

admin 更改状态以发布 2023年5月20日
0
0 Comments

如果您绝对需要实现100%的代码覆盖率-这方面的优点可以在其他地方辩论 🙂 - 您可以在您的测试中使用反射来实现它。 通常,当我实现只包含静态组件的实用程序类时,我会添加一个私有构造函数以确保不能创建该类的实例。例如:

/** 
 * Constructs a new MyUtilities.
 * @throws InstantiationException
 */
private MyUtilities() throws InstantiationException
{
    throw new InstantiationException("Instances of this type are forbidden.");
}

然后,您的测试可能看起来像这样:

@Test
public void Test_Constructor_Throws_Exception() throws IllegalAccessException, InstantiationException {
    final Class cls = MyUtilties.class;
    final Constructor c = cls.getDeclaredConstructors()[0];
    c.setAccessible(true);
    Throwable targetException = null;
    try {
        c.newInstance((Object[])null);
    } catch (InvocationTargetException ite) {
        targetException = ite.getTargetException();
    }
    assertNotNull(targetException);
    assertEquals(targetException.getClass(), InstantiationException.class);
}

基本上,在这里所做的是通过名称获取类,查找该类类型的构造函数,将其设置为public(setAccessible调用),使用不带参数的构造函数调用它,然后确保抛出的目标异常是InstantiationException

无论如何,正如您所说,这里的100%代码覆盖率要求有点麻烦,但听起来它已经超出了您的掌控范围,所以您无法做太多事情。我实际上在自己的代码中使用了类似上面的方法,并且我确实发现它有益处,但并不是从测试的角度来看。相反,它只是帮助我了解了更多的反射知识:)

0
0 Comments

有几种解决方案:

  1. 您可以添加一个公共构造函数并从测试中调用它。虽然没有意义,但也不会对代码造成太大损害。

  2. 创建一个虚假的静态实例(可以在此调用私有构造函数)。丑陋,但您可以为字段命名以传达您的意图(JUST_TO_SILENCE_COBERTURA是一个不错的名称)。

  3. 您可以让您的测试类扩展帮助类。这将固有地调用默认构造函数,但您的帮助类不能再是final了。

我特别建议最后一种方法,尤其是因为该类现在不能再是final。如果您代码的使用者想要添加另一个辅助方法,他们现在可以扩展现有类并获得一个句柄来获取所有辅助方法。这样就创建了一个辅助方法之间的耦合,传达了意图(这些方法应该放在一起)-如果帮助类是final则这是不可能的

如果您想要防止用户意外实例化帮助类,请将其定义为abstract而不是使用隐藏的构造函数。

0