使用包私有方法以便于单元测试是一个好习惯吗?

时间:2015-03-05 00:09:50

标签: java unit-testing encapsulation

有些时候,我发现自己遇到的情况是,如果我将某些方法的可见性从私有更改为私有,以便更容易进行单元测试模拟,断言......

一个例子就是这个

假设我有一个对象A,它包含4个属性X,Y,Z和R,其中X,Y和Z是集合,R是每个集合的不同元素之间的关系,例如,一个关系将由一个元素组成X,Y的元素和Z的元素。对象A不允许直接访问X,Y,Z或R,而是提供丰富的API,允许您在X,Y和Z上创建新元素,允许您将这些元素混合到新的R元素中。对于单元测试,使用公共getX(),public getY(),public getZ()和public getR()方法非常方便,因此每次调用时我都可以对对象的内部做出确切的断言。对象API。但是,暴露X,Y和Z是我想要防止的,这就是为什么从非常开始的对象使这些元素变得私有,并且只使用它的API提供对它们的间接访问。然而,提供包私有方法getX(),getY(),getZ()和getR()是否有意义,以便至少形成单元测试我可以轻松检查对象的内部状态是否是预期的?< / p>

缺点当然是方法的可见性增加,并且鉴于这种方法是私有的,有充分的理由,感觉有点奇怪。

当然我可以用反射来实现同样的效果,但感觉更脏。

所以问题是,这是一种好的还是坏的做法?这是代码味吗?它会发生在别人身上吗?有更好的技术吗?

5 个答案:

答案 0 :(得分:3)

通常,良好做法是公开内部逻辑。相反,你必须使你的类可配置。例如,如果您的类需要其他组件,例如让HttpComponent等等,请尝试使用不同的依赖注入技术来提供这些依赖项。然后在测试中,您可以模拟这些依赖项并验证那些模拟。

在您的情况下,它取决于上下文。大多数情况下,您将私有函数作为测试公共函数的一部分进行测试。因此,您测试不同情况下的公共行为,如果全部通过它意味着通过该公共函数调用的私有函数也可以工作。

答案 1 :(得分:1)

如果您想测试私有方法,您可以选择以下几种方法:

  1. 依赖注入
  2. 如果你真的需要测试一个私有方法,那么该方法实际上应该是另一个类的公共方法(代码味道)。这意味着如果您在“ A ”类中使用私有方法“ m ”,则可以考虑将“ m ”作为公开类“ B ”中的方法,然后将'B'注入'A'

    这种技术很常见,而且大部分时间都可以解决这个问题。然而,只有当您将大部分代码从原始类('A')移动到新类('B')时,它才有意义。

    此解决方案 Mockito 友好。

    1. 测试双重继承
    2. 将班级'A'中隐私方法'm'的可见性更改为受保护。然后在测试文件夹中创建一个扩展'A'的类'B'。最后,在'B'中创建一个公共方法'pm',其签名与'm'相同,只需调用'm “即可。通过这种方式,您可以在'A'中“制作”不可见的'm'方法,但中的'pm'可以访问 B'

      此解决方案也 Mockito 友好。

      1. Groovy的
      2. 使用Groovy等JVM动态语言,允许您调用私有方法。

        1. 反思
        2. 使用反射获取私有方法,然后更改其可见性。请参阅this

          1. 包装可见性
          2. 将方法声明为包(无可见性约束)并在同一包中声明测试类。我个人不喜欢使用这个,因为我没有找到优雅的Java包的可见性。

答案 2 :(得分:0)

如果A管理X,Y,Z和R,听起来像是做了太多事情。

也许一个好主意是重构你的代码,使R成为一个单独的类,它将X,Y和Z作为输入参数。如果您愿意,可以将课程设为私人。无论如何,你可以通过提供不同的X,Y和Z来直接测试R.

答案 3 :(得分:0)

一般的建议是仅测试该类的公共API(调用私有API并进行测试)。否则,在重构内部API的情况下,您将需要重构大多数测试。

答案 4 :(得分:-1)

对于单元测试,您可能会遇到一些测试和模拟私有,静态方法和构造函数的问题。因此,您可以选择使用以下两种解决方案之一:

  1. 不要使用私有方法,并使它们可见。也不要使用静态方法并将它们放在单例类中。

  2. 使用执行诸如powermock之类的测试的模拟库。它还可以模拟构造函数和静态方法。

  3. 糟糕或良好的解决方案,我想没有,它取决于项目的策略,以及决定进行测试。