2012-03-14 85 views
27

我使用JUnit4和Cobertura仅使用静态方法来测试帮助程序类。测试方法很容易,已经完成。JUnit:仅使用静态方法测试帮助程序类

但是,cobertura显示该类未完全覆盖测试,因为它未在任何地方实例化。

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

然后cobertura抱怨空的私人构造函数未被测试覆盖。

是否有任何解决方案来实现100%的代码覆盖这种情况?

代码覆盖率是来自顶级管理(在这种情况下)的要求,所以对于我为这个特定类获得100%是相当有帮助的。

回答

27

有几种解决方案:

  1. 您可以添加一个公共构造函数,并从测试调用它。虽然它没有意义,但它也不会伤害(很多)。

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

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

我建议最后一种方法,特别是因为班级不能再final。如果您的代码的使用者想要添加另一个帮助器方法,他们现在可以扩展现有的类并接收一个句柄以获取所有帮助器方法。这就形成了其通信的意图的辅助方法的耦合(这属于一起) - 这是不可能的,如果辅助类是final

如果要防止用户意外初始化助手类,使它abstract而不是使用一个隐藏的构造函数。

+1

第三种方法在我看来是最好的,因为它根本不影响代码(只有测试)。我会采取这种方式。谢谢你的帮助。 – 2012-03-14 11:43:16

2

除非你显式调用私有构造函数(这将是糟糕的代码),你将无法覆盖这些行。

7

在所有情况下获得100%的覆盖率都很好,但在某些情况下这是不可能的。当然,如果你有一个从未实例化过的类,Cobertura会将其作为一个不完整的测试覆盖率,因为这些代码行实际上在类中,但它们没有经过测试。事实上,你永远不会调用一个私有构造函数(我假设你已经隐藏了构造函数,因为它是私人的),所以我不打扰。测试应该是关于如何得到你所期望的,虽然我同意100%覆盖率是好的,但在某些情况下(如这样),这是没有用的。

看看100% Code Coverage以及。

+2

有时代码覆盖需要从顶层管理(在这种情况下),所以对于我来说,为这个特定类获得100%是相当有帮助的。是的 - 我知道这种方法的荒谬。但是 - 感谢您的文章链接。 – 2012-03-14 11:41:44

27

如果您绝对需要实现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); 
} 

基本上,你在做什么在这里越来越名字的类,这个类的类型寻找构造,设置它公开(调用setAccessible),调用没有参数的构造函数,然后确保抛出的目标异常是InstantiationException

无论如何,正如你所说的,这里100%的代码覆盖率要求是一种痛苦,但它听起来好像不在你的手中,所以你对此无能为力。实际上,我在自己的代码中使用了与上面类似的方法,并且我确实发现它有益处,但不是从测试角度来看。相反,它只是帮助我学习更多关于思​​考的知识,而不是我之前所知道的:)

+1

+1 Nice hack :-) – 2012-03-14 16:33:54

+0

+1,聪明的解决方案! – JW8 2012-09-25 21:13:38

+0

为什么在catch块中存在'return'?测试将始终返回true。 ;) – 2015-05-14 06:01:58