JUnit 测试私有变量? [复制]

Posted

技术标签:

【中文标题】JUnit 测试私有变量? [复制]【英文标题】:JUnit Testing private variables? [duplicate] 【发布时间】:2011-10-05 09:37:34 【问题描述】:

我被分配了对一个我从未直接使用 JUnit 进行过的类进行单元测试的任务,并且严禁更改包中的代码。这通常没有问题,因为我们的大多数单元测试只是为了功能和输入/输出的一致性,这可以通过运行例程并检查它们的返回值来完成。

但是,偶尔需要检查类中的私有变量,或者直接编辑私有变量来检查一些内部行为。有没有办法访问这些,无论是通过 JUnit 还是任何其他方式,以进行单元测试,而无需实际更改原始源包中的任何代码?如果不是,那么在单元测试员与编码员可能不是同一个人的现实世界中,程序员如何处理这个问题?

【问题讨论】:

反射怎么样?还是在测试中通过代码编织添加getter和setter? 公共字段和方法的实现不就是使用内部行为吗?如果不是,它的目的是什么? 我更喜欢执行导致私有字段更改其状态的流程。然后执行新流程。 imo,私有字段的存在是为了保存一些先前的行为,这反过来会影响下一个行为。所以单元测试仍然是面向行为而不是面向实现的,因为你从代码中推断出行为,这在你不是所有者时很常见。 @Hanif,如果私有字段也只在回调中修改怎么办?你怎么解决这个问题。我面临一个类似的问题,其中私有变量在回调中设置,我需要设置私有变量才能测试其他一些方法。 【参考方案1】:

首先,您现在处于不利的境地 - 需要为您最初创建的代码编写测试并且没有任何更改 - 噩梦!与您的老板交谈并解释,如果不使其“可测试”,就无法测试代码。为了使代码可测试,您通常会做一些重要的更改;

关于私有变量。你实际上永远不应该那样做。旨在测试私有变量是当前设计出现问题的第一个迹象。私有变量是实现的一部分,测试应该关注行为而不是实现细节。

有时,私有字段会通过一些 getter 暴露给公共访问。我这样做,但尽量避免(在 cmets 中标记,例如“用于测试”)。

由于您无法更改代码,我看不到检查私有变量的可能性(我的意思是真正的可能性,不像反射黑客等)。

【讨论】:

拥有单独的代码和测试开发人员可能是一个优势,因为它需要 2 个人来解释规范。如果它们的解释不同,则要求不够清晰,测试可能会失败,并且您已经检测到可能的错误。太好了! @Kwebble 我的经验表明,分离“编码员”和“测试员”是一种非常糟糕的做法。 ) @donnyton:我希望你的测试不会失败,因为无论如何这都需要更改代码。可能具有相同的效果。 假设这是一项真正的任务(而不仅仅是老板想看看你如何编码的任务;)),这是老板/项目经理必须是已经参与其中的人的另一个原因软件开发/测试。 您实际上并没有提供问题的答案。而且我不明白为什么您不应该在测试中访问私有变量。那么如何测试不可变类呢?【参考方案2】:

如果您在单独的文件夹中创建测试类,然后将其添加到构建路径中,

然后你可以通过正确使用包来设置命名空间,使测试类成为被测类的内部类。这使它可以访问私有字段和方法。

但不要忘记从发布构建的构建路径中删除该文件夹。

【讨论】:

【参考方案3】:

尽管陈述显而易见的危险:通过单元测试,您希望测试对象的正确行为 - 这是根据其公共接口定义的。您对对象如何完成此任务不感兴趣 - 这是一个实现细节,对外不可见。这就是发明 OO 的原因之一:实现细节是隐藏的。所以测试私有成员没有意义。你说你需要100%的覆盖率。如果有一段代码无法使用对象的公共接口进行测试,那么这段代码实际上永远不会被调用,因此是不可测试的。删除它。

【讨论】:

通常无法在不修改的情况下从公共接口对代码进行单元测试。【参考方案4】:

我不知道您是否发现了一些需要您针对私有字段进行测试的特殊情况代码。但根据我的经验,你永远不必测试私人的东西——总是公开的。也许您可以举一个需要测试私有代码的示例?

【讨论】:

不幸的是我不能给出示例代码。私有成员的测试来自于 100% 代码覆盖测试的管理要求(而不是简单的功能测试或输入/输出测试)。如果你问我,它不是很有用,但不幸的是,它是一个困扰程序员的必需协议。 听起来你的经理参加了一些蹩脚的课程,告诉他/她 100% 的代码覆盖率是个好主意。这让我很难过。我和你有感觉:) 我创建了一个带有私有常量的类,用作文件保存的文件散列结尾。我必须将散列传递给函数以使其可测试,因为如果程序发现错误的散列,则应该加载旧文件,而测试它的唯一方法是为其提供新的散列。可能会称之为糟糕的设计。【参考方案5】:

是的,您可以使用反射来访问私有变量。虽然不是一个好主意。

看看这个:

http://en.wikibooks.org/wiki/Java_Programming/Reflection/Accessing_Private_Features_with_Reflection

【讨论】:

并查看 dp4j.com 以避免自己编写反射代码 如果你详细说明为什么不是好主意但你仍然提出它会很好.. 查看了大量有关此问题的帖子后。终于找到了帮助我 +1 的解决方案。 最好在您的答案中除了链接之外添加解决方案的摘要,因为该链接将来可能无法使用。【参考方案6】:

Reflection 例如:

public class PrivateObject 

  private String privateString = null;

  public PrivateObject(String privateString) 
    this.privateString = privateString;
  

PrivateObject privateObject = new PrivateObject("The Private Value");

Field privateStringField = PrivateObject.class.
            getDeclaredField("privateString");

privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(privateObject);
System.out.println("fieldValue = " + fieldValue);

【讨论】:

当我尝试使用您的技术时,我收到一个错误“没有此类字段异常”。 上述方法仅适用于在目标中声明字段而不是在父类中声明的情况。 Class 类中还有其他方法可以让您获得父声明字段而不是 getDeclaredField(String)。

以上是关于JUnit 测试私有变量? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ES6 中使用私有变量? [复制]

公共类,但私有成员变量? [复制]

评估一个静态私有变量(Java),不应该是非法的吗? [复制]

如何在 Python 中使私有变量可访问? [复制]

为啥伴随对象不使用 JUnit 测试作为私有字段进行测试?

从测试访问私有变量并完成覆盖功能