关于java:JUnit:仅使用静态方法测试助手类

JUnit: testing helper class with only static methods

我正在用JUnit4和Cobertura测试一个只使用静态方法的助手类。测试方法很简单,已经完成了。

但是,cobertura表明类没有完全被测试覆盖,因为它没有在任何地方实例化。

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

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

对于这种情况,是否有实现100%代码覆盖率的解决方案?

顶级管理层(在本例中)需要代码覆盖率,因此对于我来说,获得这个特定类的100%是非常有帮助的。


有几种解决方案:

  • 可以添加公共构造函数并从测试中调用它。虽然它没有意义,但它也没有多大的伤害。

  • 创建一个虚拟静态实例(您可以在这里调用私有构造函数)。丑陋,但你可以给字段一个名字来传达你的意图(JUST_TO_SILENCE_COBERTURA是一个好名字)。

  • 您可以让测试扩展helper类。这本质上会调用默认的构造函数,但您的助手类不能再是final

  • 我建议使用最后一种方法,特别是因为类不能再是final。如果代码的使用者想要添加另一个helper方法,那么他们现在可以扩展现有的类并接收一个句柄来获取所有helper方法。这就创建了一个helper方法的耦合,它传递了意图(它们属于一起),如果helper类是final的话,这是不可能的。

    如果要防止用户意外地实例化helper类,请将其设置为abstract,而不是使用隐藏的构造函数。


    如果您绝对需要实现100%的代码覆盖率——这一点的优点可以在其他地方讨论:)——您可以在测试中使用反射来实现它。作为习惯,当我实现一个仅静态的实用程序类时,我会添加一个私有的构造函数来确保类的实例不能被创建。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    /**
     * Constructs a new MyUtilities.
     * @throws InstantiationException
     */

    private MyUtilities() throws InstantiationException
    {
        throw new InstantiationException("Instances of this type are forbidden.");
    }

    那么您的测试可能看起来像这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @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%代码覆盖率要求有点痛苦,但听起来这是您无法控制的,所以您几乎无能为力。实际上,我在自己的代码中使用了与上面类似的方法,我确实发现这是有益的,但不是从测试的角度。相反,它只是帮助我学到了比以前更多的关于思考的知识。


    在所有情况下获得100%的覆盖率是好的,但在某些情况下这是不可能的。当然,如果您有一个从未实例化的类,那么cobertura将得到一个不完整的测试覆盖率,因为这些代码行实际上在类中,但它们没有被测试。

    事实上,您永远不会调用私有构造函数(我假设您已通过使其私有化来隐藏该构造函数),所以我不会麻烦您。测试应该是得到你所期望的,虽然我同意100%的覆盖率是好的,但在某些情况下(像这样),这是没有用的。

    看看100%的代码覆盖率。


    不。

    除非您显式地调用私有构造函数(这将是错误的代码),否则您将无法覆盖这些行。